Entity Framework Core - 更新相关集合

Kub*_*uba 6 c# entity-framework entity-framework-core asp.net-core

我正在尝试更新 ProjectModel 中的 ProjectEmployees 集合。我想删除所有旧值并设置新值。

我的模型:

public class Project
{
    ... 
    public ICollection<ProjectEmployee> ProjectEmployees { get; set; }
}

public class ProjectEmployee
{
    public int ProjectId { get; set; }
    public virtual Project Project { get; set; }
    public int UserId { get; set; }
    public virtual Employee Employee { get; set; }
}

public class Employee
{
    public int UserId { get; set; }
    public User User { get; set; }
    ...
}
public class ProjectGroupModel //ViewModel
{
    public int ProjectId { get; set; }
    public ICollection<Employee> ProjectEmployees { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是典型的多对多关系。

我的控制器动作:

    [HttpPost("group")]
    public async Task<IActionResult> CreateGroup([FromBody] ProjectGroupModel pro)
    {
            var dbProject = await _context.Project
                .Include(p=>p.ProjectEmployees)
                .FirstAsync(p => p.ProjectId == pro.ProjectId);
            dbProject.ProjectEmployees.Clear();

            foreach (var emp in pro.ProjectEmployees)
            {
                dbProject.ProjectEmployees.Add(new ProjectEmployee()
                {
                    UserId = emp.UserId
                });
            }

            await _context.SaveChangesAsync();

            return Ok();
    }
Run Code Online (Sandbox Code Playgroud)

当 pro.ProjectEmployees 为空时,dbProject.ProjectEmployees 中的所有记录都被正确删除,如果 dbProject.ProjectEmployees 为空,则会添加模型中的新记录,但是当 dbProject.ProjectEmployees 不为空时,我无法设置新记录:

错误:

“无法跟踪实体类型‘ProjectEmployee’的实例,因为已经在跟踪具有相同键的此类型的另一个实例。添加新实体时,对于大多数键类型,如果未设置键,将创建唯一的临时键值(即如果键属性为其类型分配了默认值。如果您为新实体明确设置键值,请确保它们不会与现有实体或为其他新实体生成的临时值冲突。附加现有实体时,请确保只有一个具有给定键值的实体实例附加到上下文。”

我试图以数百种方式修复此操作,但始终是错误的。

Iva*_*oev 4

它远非完美,但我能够使其工作的唯一方法是从相应的项目中删除项目DbSetSaveChanges在添加新项目之前调用:

    var dbProject = await _context.Project
        .Include(p=>p.ProjectEmployees)
        .FirstAsync(p => p.ProjectId == pro.ProjectId);

    if (dbProject.ProjectEmployees.Any())
    {
        _context.ProjectEmployee.RemoveRange(dbProject.ProjectEmployees);
        await _context.SaveChangesAsync();
    }

    foreach (var emp in pro.ProjectEmployees)
    {
        dbProject.ProjectEmployees.Add(new ProjectEmployee()
        {
            UserId = emp.UserId
        });
    }
    
    await _context.SaveChangesAsync();
Run Code Online (Sandbox Code Playgroud)