簡體   English   中英

實體框架核心 - 更新相關集合

[英]Entity Framework Core - update related collection

我正在嘗試更新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; }
}

這是典型的多對多關系。

我的控制器動作:

    [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();
    }

當pro.ProjectEmployees為空時,dbProject.ProjectEmployees中的所有記錄都被正確刪除,如果dbProject.ProjectEmployees為空,則添加了來自model的新記錄,但是當dbProject.ProjectEmployees不為空時,我無法設置新記錄:

錯誤:

“無法跟蹤實體類型'ProjectEmployee'的實例,因為已經跟蹤了具有相同密鑰的此類型的另一個實例。添加新實體時,對於大多數密鑰類型,如果未設置密鑰,則將創建唯一的臨時密鑰值(即,如果為鍵屬性指定了其類型的默認值,則。如果要為新實體顯式設置鍵值,請確保它們不會與現有實體或為其他新實體生成的臨時值發生沖突。附加現有實體時,請確保只有一個具有給定鍵值的實體實例附加到上下文。“

我試圖以數百種方式修復這個動作,但總是錯誤的。

另一個SO問題相關聯

我可以在這里和你的班級一起回答。

然后使用此擴展我刪除未選中並將新選擇添加到列表中

    public static void TryUpdateManyToMany<T, TKey>(this DbContext db, IEnumerable<T> currentItems, IEnumerable<T> newItems, Func<T, TKey> getKey) where T : class
    {
        db.Set<T>().RemoveRange(currentItems.Except(newItems, getKey));
        db.Set<T>().AddRange(newItems.Except(currentItems, getKey));
    }

    public static IEnumerable<T> Except<T, TKey>(this IEnumerable<T> items, IEnumerable<T> other, Func<T, TKey> getKeyFunc)
    {
        return items
            .GroupJoin(other, getKeyFunc, getKeyFunc, (item, tempItems) => new { item, tempItems })
            .SelectMany(t => t.tempItems.DefaultIfEmpty(), (t, temp) => new { t, temp })
            .Where(t => ReferenceEquals(null, t.temp) || t.temp.Equals(default(T)))
            .Select(t => t.t.item);
    }

使用它看起來像這樣

 var model = db.Employees
             .Include(x => x.ProjectEmployees)
             .FirstOrDefault(x => x.EmployeeId == employee.EmployeeId);

 db.TryUpdateManyToMany(model.ProjectEmployees, listOfNewProjectIds
 .Select(x => new ProjectEmployee
 {
     ProjectId = x,
     EmployeeId = employee.EmployeeId
 }), x => x.ProjectId );

它遠非完美,但我能夠使其工作的唯一方法是從相應的DbSet刪除項目並在添加新的之前調用SaveChanges

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();

我認為舊的對象並沒有真正從數據庫中刪除。 你只是調用Clear()這還不夠。 試着這樣做:

[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);

    foreach (var old in dbProject.ProjectEmployees)
        {
            _context.ProjectEmployee.Remove(old);
        }

    dbProject.ProjectEmployees.Clear();

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

    await _context.SaveChangesAsync();

    return Ok();
}

在這里,我假設您在上下文中有適當的設置(_context.ProjectEmployee)。 如果您在上下文中沒有明確地使用此Set,則只需添加它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM