Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架:更新包含在Net Core 3中的记录_C#_.net_Entity Framework_.net Core_Entity Framework Core - Fatal编程技术网

C# 实体框架:更新包含在Net Core 3中的记录

C# 实体框架:更新包含在Net Core 3中的记录,c#,.net,entity-framework,.net-core,entity-framework-core,C#,.net,Entity Framework,.net Core,Entity Framework Core,如何使用实体框架核心中的includes更新表?以下内容似乎更新了客户事务,但没有更新产品Id 客户和产品的属性都会发生变化,但CustomerId和ProductId保持不变 public void ModifyTransaction(IEnumerable<CustomerTransaction> customerTransactionList) { foreach (var modifyItem in customerTransactionList) {

如何使用实体框架核心中的includes更新表?以下内容似乎更新了客户事务,但没有更新产品Id

客户和产品的属性都会发生变化,但CustomerId和ProductId保持不变

public void ModifyTransaction(IEnumerable<CustomerTransaction> customerTransactionList)
{
    foreach (var modifyItem in customerTransactionList)
    {
        var existingItem = _dbContext.Set<CustomerTransaction>().Include(x => x.Product)
                                        .FirstOrDefault(x => x.CustomerTransactionId == modifyItem.CustomerTransactionId );

        if (existingItem == null)
        {
            _dbContext.Add(existingItem );
        }
        else
        {
            _dbContext.Entry(existingItem).State = EntityState.Modified;
        }
    }
    _dbContext.SaveChanges();
}
公共作废修改事务(IEnumerable customerTransactionList)
{
foreach(customerTransactionList中的var modifyItem)
{
var existingItem=_dbContext.Set().Include(x=>x.Product)
.FirstOrDefault(x=>x.CustomerTransactionId==modifyItem.CustomerTransactionId);
if(existingItem==null)
{
_添加(现有项);
}
其他的
{
_条目(existingItem).State=EntityState.Modified;
}
}
_dbContext.SaveChanges();
}

使用Net Core 3.1时,此代码容易出现错误,这些错误会根据场景而逐渐增加。在客户机和服务器之间传递实体类时,重要的是要了解传递回服务器的对象只是序列化副本,而不是跟踪的实体。由于序列化的工作方式,DbContext获取两个事务记录(都引用ID为14的产品)将引用同一实体实例,因此反序列化时,同一对事务将有两个单独的对象引用,每个对象引用的产品ID为14

根据您的示例,您至少需要执行以下操作:

foreach (var modifyItem in customerTransactionList)
{
    var existingItem = _dbContext.CustomerTransactions
         .Include(x => x.Product)
         .SingleOrDefault(x => x.CustomerTransactionId == modifyItem.CustomerTransactionId );
    var trackedProduct = _dbContext.Products.Local(x => x.ProductId == modifyItem.Product.ProductId).SingleOrDefault();
    if (trackedProduct != null)
       modifyItem.Product = trackedProduct;
    else
       _dbContext.Products.Attach(modifyItem.Product);
    
    if (existingItem == null)
        _dbContext.Add(modifyItem);
    else
    {
        _dbContext.Entry(existingItem).CurrentValues.SetValues(modifyItem);
        if(existingItem.Product.ProductId != modifyItem.Product.ProductId)
            existingItem.Product = modifyItem.Product; // tracked reference.
    }
}
_dbContext.SaveChanges();
}

这相当于像您正在做的那样检查现有事务。但是,我们还必须检查DbContext可能跟踪的相关实体(产品)的任何缓存副本。如果我们不这样做,并且我们尝试添加一个具有与上下文已跟踪的ID匹配的产品的交易,我们将获得PK违规或创建了新产品ID的重复产品记录,具体取决于产品PK的配置方式。(即,
DatabaseGenerated.Identity
column)如果找到本地缓存实例,我们将使用本地缓存实例更新产品引用,否则我们会告诉DbContext开始跟踪产品实例。这假设此方法不能接受新的产品作为调用的一部分,并且收到的产品记录应该合法存在。处理新产品和验证传入的产品需要额外的条件代码和DB检查。从这里,我们确定事务是更新还是插入。在更新的情况下,我们可以使用
CurrentValues.SetValues
跨值复制(如上所述)或自动映射,或手动跨值复制相关值。假设一个事务可能会更改产品,我们也会根据修改后的产品ID检查产品ID,如果不同,我们会更新产品参考<代码>修改项。此时的产品将指向DbContext跟踪的引用


使用这样的方法更新实体可能非常复杂,因为您不仅要考虑检测新记录和现有记录,还要考虑更新对DbContext已经跟踪的实体的引用。我强烈建议采用视图模型进行显式的添加和更新操作,并尽可能原子化地处理操作。也就是说,与其传递可能包含更新或插入的事务集合,不如对每种单一类型的更改进行更细粒度的调用。(操作更简单、更快,出错的地方更少)

您尚未对实体进行任何更改。需要更新哪些内容?