EF:使用添加,删除或未更改的子实体更新实体(多对多关系)

时间:2017-06-01 17:55:02

标签: c# entity-framework many-to-many

这是我第一次在asp.net mvc应用程序中使用EF。在过去的两天里,我正在阅读类似的问题和例子,但到目前为止,我还没有完全理解我必须做的事情。

我有两个有多对多关系的实体。

型号:

[Table("Unit")]
public class UnitEntity
{
    [Required]
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    [Required]
    public UnitType Type { get; set; }

    [StringLength(255)]
    public string Title { get; set; }

    ///some other properties

    public virtual ICollection<UserEntity> Users { get; set; }
}

[Table("User")]
public class UserEntity
{
    [StringLength(255)]
    public string Id { get; set; }

    [Required]
    public string UserName { get; set; }

    [Required]
    public string Email { get; set; }


    public int Status { get; set; }

    // some other properties

    public virtual ICollection<UnitEntity> DepartmentUnits { get; set; }
}

在我的dbcontext中:

public virtual DbSet<UnitEntity>  Units { get; set; }
public virtual DbSet<UserEntity> Users { get; set; }

 modelBuilder.Entity<UserEntity>()
           .HasMany(e => e.DepartmentUnits)
           .WithMany(e => e.Users)
           .Map(m => m.ToTable("UserDepartments").MapLeftKey("UserId").MapRightKey("DepartmentId"));

使用Multiselect List在视图中更新每个用户的DepartmentUnits列表并传递给控制器​​。

控制器方法:

    [HttpPost]
    public ActionResult UpdateUser(ExternalUserDTO userdata)
    {
        //list of UnitDepartments from the view
        var userDepartments = new List<UnitEntity>();
        foreach (var unitid in userdata.DepartmentIds)
        {
            userDepartments.Add(manager.GetUnit(unitid));
        }


        //create new user with data to update 
        UserEntity userentity = new UserEntity()
        {
            Id = userdata.Id,
            DepartmentUnits = userDepartments,
            Status = userdata.Status

        };


        userManager.UpdateUser(userentity);

        return new JsonResult { Data = new { Success = false } };
    }

在UserManager类中:

public void UpdateUser(UserEntity entity)
    {
        var updentity = this.dataContext.Users.Find(entity.Id);

        if (updentity == null)
            throw new NullReferenceException("User not found");


        updentity.Status = entity.Status;

        var newUnitIds = entity.DepartmentUnits.Select(u => u.Id);
        var existingUnitIds = updentity.DepartmentUnits.Select(u => u.Id);

        updentity.DepartmentUnits.Where(u => !newUnitIds.Contains(u.Id)).ToList().ForEach(d => updentity.DepartmentUnits.Remove(d));
        entity.DepartmentUnits.Where(u => newUnitIds.Except(existingUnitIds).Contains(u.Id)).ToList().ForEach(d => updentity.DepartmentUnits.Add(d));


        this.dataContext.Entry(updentity).State =  EntityState.Modified;


        foreach (var deptentity in updentity.DepartmentUnits)
        {
            if(newUnitIds.Contains(deptentity.Id))
            {
                this.dataContext.Entry(deptentity).State = EntityState.Added;
            }
            if(existingUnitIds.Contains(deptentity.Id))
            {
                this.dataContext.Entry(deptentity).State = EntityState.Unchanged;
            }
        }


        try
        {
            this.dataContext.SaveChanges();

        }
        catch (Exception)
        {
            throw new Exception("Update problem");
        }

    }

我需要更新我的UserDepartments表(请参阅上面的模型构建器),以便删除已删除的,添加新的并保留特定用户的现有DepartmentUnit。以上不起作用,我很遗憾,我感谢你的帮助。

2 个答案:

答案 0 :(得分:1)

只要dataContext变量生命周期为单个UpdateUser操作的范围,您就可以让EF更改跟踪器通过从数据库加载目标实体来完成大部分工作, 包括有问题的集合,然后简单地将其替换为从传递的实体的相应集合创建的存根实体列表:

public void UpdateUser(UserEntity entity)
{
    // Load the exiting entity from the db, including the collection
    var dbEntity = this.dataContext.Users
        .Include(e => e.DepartmentUnits)
        .FirstOrDefault(e => e.Id == entity.Id);

    if (dbEntity == null)
        throw new NullReferenceException("User not found");

    // Update the master information
    this.dataContext.Entry(dbEntity).CurrentValues.SetValues(entity);

    // Replace the collection with stubs created from the source collection
    dbEntity.DepartmentUnits = entity.DepartmentUnits.Select(e => new UnitEntity { Id = e.Id }).ToList();

    // And that's all - EF change tracker will detect added/removed/unchanged links (and changed master properties) for you.
    // Just commit the changes and you are done.
    this.dataContext.SaveChanges();
}

请注意,这适用于EF6。 EF Core目前需要更多类似于您尝试过的手动工作。

答案 1 :(得分:0)

工作代码:

public void UpdateUser(UserEntity entity)
    {

        var updentity = this.dataContext.Users.Include(e => e.DepartmentUnits).FirstOrDefault(e => e.Id == entity.Id);


        if (updentity == null)
            throw new NullReferenceException("User not found");


        updentity.Status = entity.Status;

        updentity.DepartmentUnits = entity.DepartmentUnits.Select(e => this.dataContext.Units.Find(e.Id)).ToList();


        try
        {
            this.dataContext.SaveChanges();

        }
        catch (Exception)
        {
            throw new Exception("Update problem");