使用列表的子记录保存记录时出现Entity Framework错误。

17 浏览
0 Comments

使用列表的子记录保存记录时出现Entity Framework错误。

在我的ASP.NET Core项目中,我们使用EF Core。当保存一个具有子记录列表的记录时,我们会遇到以下错误:

实体类型Child的实例无法被跟踪,因为已经有另一个具有相同键值{'Id'}的实例被跟踪。

步骤如下:

1. 从控制器中获取记录并传递给视图(视图具有一个)

2. 通过HTML表单更新一些属性

3. 点击保存

4. 在控制器的Save方法中捕获传递的模型。从数据库中获取原始项目并保存更改(通过表单进行的更改)

5. 在存储库中调用更新/保存操作

简化的代码如下:

// 从数据库中获取记录
var record = _dbContext.Parents
    .Include(x => p.SomeOtherObject)
    .Include(x => x.ListChildren)
    .FirstOrDefault(x => x.IdParent == id);
// 对Parent和ListChildren进行一些更改
// 对SomeOtherObject不进行任何更改!!!
// 保存更改
_dbContext.Update(record);
_dbContext.SaveChanges();
// 实体定义
public class Parent
{
    public int IdParent { get; set; }
    public string Name {get; set;}
    public string Surname {get; set;}
    public int IdSomeOtherObject { get; set; }
    [ForeignKey("IdSomeOtherObject")]
    public virtual SomeOtherObject SomeOtherObject { get; set; }
    public virtual List ListChildren { get; set; }
}
public class Child
{
    public int IdChild { get; set; }
    public int IdParent { get; set;}
    public string Name { get; set; }
}
public class SomeOtherObject
{
    public int IdSomeOtherObject { get; set; }
    public string PropertiesBlahBla { get; set; }
}

现在,我知道我们可以在Get操作中添加.AsNoTracking(),但问题是当保存Parent时,EntityFramework会针对SomeOtherObject执行UPDATE SQL语句(即使它没有以任何方式更改),这对于我们的数据/输入场景是不可接受的。

是否有其他方法可以解决这个错误?

0
0 Comments

问题的出现原因是在保存具有子记录列表的记录时出现了EntityFramework错误。解决方法是尝试移除_dbContext.Update(record);代码,因为实体应该已经被跟踪,所以改动会被保存。根据Update文档所述,它会开始跟踪给定的实体和可从给定实体访问的条目,默认使用Modified状态。因此在这种情况下,它是不需要的。

在讨论中发现,子跟踪集合是这样替换的:

record.ListChildren = someModel.ListChildren.Where(...).ToList()

。这导致了添加具有已被跟踪的ID的元素。所以应该按照建议的方法更新ListChildren,像这里建议的一样。

完整的错误信息如下:'The instance of entity type '' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.'

你的数据库上下文是否有范围?还要检查在调用之前context.ChangeTracker.Entries()是否为空。另外,你能否提供一个最小可复现的示例?

startup.cs中,我们使用services.AddScoped<xyz, xyz>();来添加服务/仓储。

当尝试检查context.ChangeTracker.Entries()时,返回的是与我之前的问题相同的错误。

如果你在获取record之前尝试访问它,这意味着错误出现在提供的代码之外(之前)。

整个解决方案/项目非常庞大,所以很难准备一个最小可复现的示例,特别是没有数据库连接的情况下...我将在上面的代码示例中添加一些额外的信息。

我尝试在获取和更新/保存更改之前访问context.ChangeTracker.Entries()。请让我们在聊天中继续讨论

0