使用EF Core 5.0。我有一个SPA页面,加载
Group
实体及其集合
Employee
API中的实体:
var groupToUpdate = await context.Groups
.Include(g => g.Employees)
.FirstOrDefaultAsync(...);
//Used for UI, list of additional employees for selective adding
var employeeList = await context.Employees.
.Where(...)
.ToListAsync();
然后用户修改
groupToUpdate
实体,包括一些非导航属性,如名称/注释。
在同一屏幕上,用户将一些员工添加到组中,从组中删除一些员工,并保留组中的一些现有员工。所有员工都是DB中具有现有主键的现有实体。到目前为止所做的所有更改都只是针对内存中断开连接的实体。
当用户单击保存时
要更新的组
实体被发送到我的后端代码。请注意,我们没有跟踪哪些员工被添加/删除/留下,我们只想让它
要更新的组
完全覆盖旧实体,特别是替换的旧集合
Employees
与新的。
为了实现这一点,后端代码首先从数据库中再次加载组,开始在上下文中跟踪它。然后我尝试更新实体,包括用新集合替换旧集合:
public async Task UpdateGroupAsync(Group groupToUpdate)
{
var groupFromDb = await context.Groups
.Include(g => g.Employees)
.FirstOrDefaultAsync(...);
// Update non-navigation properties such as groupFromDb.Note = groupToUpdate.Note...
groupFromDb.Employees = groupToUpdate.Employees;
await context.SaveChangesAsync();
}
现在,如果更改为
员工
集合是完全替换(删除所有旧的,添加所有新的),此方法成功。但只要有一些
员工
则EF核心抛出异常:
无法跟踪实体类型“Employee”的实例,因为另一个具有键值的实例。。。已被跟踪
看来EF Core试图追踪
受雇者
使用从数据库中新加载的实体
groupFromDb
和来自的
要更新的组
,即使后者仅作为参数从断开状态传入。
我的问题是,如何以最少的复杂性处理这种更新?是否有必要手动跟踪添加/删除的实体并添加/删除它们,而不是试图替换整个集合?