我目前正在学习使用Entity Framework在新的MVC应用程序中使用它。我有一些努力在两个表之间设置多对多关系,但是它使它能够显示数据。但是,在更新实体时,EF会为链接表插入重复记录。
BusinessUnit
展示将WindowsLogins
和WindowsGroups
组合在一起的实体,以便通过BusinessUnit使用。 BusinessUnitWindowsLogin和BusinessUnitWindowsGroup充当多对多关系的联结表。
实体在C#中定义如下:
BusinessUnit
public class BusinessUnit
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public bool IsPersonal { get; set; }
public virtual IList<WindowsGroup> WindowsGroups { get; set; }
public virtual IList<WindowsLogin> WindowsLogins { get; set; }
}
WindowsGroup(WindowsLogin类似)
public class WindowsGroup
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Domain { get; set; }
public string Name { get; set; }
public ICollection<BusinessUnit> BusinessUnits { get; set; }
}
我在我的DbContext的OnModelCreating
方法中写了这个来注册连接表和外键:
modelBuilder.Entity<BusinessUnit>()
.HasMany(businessUnit => businessUnit.WindowsGroups)
.WithMany(windowsGroup => windowsGroup.BusinessUnits)
.Map(mc =>
{
mc.MapLeftKey("BusinessUnitId");
mc.MapRightKey("WindowsGroupId");
mc.ToTable("BusinessUnitWindowsGroup", "Config");
});
modelBuilder.Entity<BusinessUnit>()
.HasMany(businessUnit => businessUnit.WindowsLogins)
.WithMany(windowsLogin => windowsLogin.BusinessUnits)
.Map(mc =>
{
mc.MapLeftKey("BusinessUnitId");
mc.MapRightKey("WindowsLoginId");
mc.ToTable("BusinessUnitWindowsLogin", "Config");
});
我写了这样的更新:
public void Update(BusinessUnit businessUnit)
{
var oldBusinessUnit = _unitOfWork.BusinessUnits.GetById(businessUnit.Id);
oldBusinessUnit.Name = businessUnit.Name;
oldBusinessUnit.WindowsGroups.Clear();
oldBusinessUnit.WindowsLogins.Clear();
oldBusinessUnit.WindowsGroups = businessUnit.WindowsGroups;
oldBusinessUnit.WindowsLogins = businessUnit.WindowsLogins;
_unitOfWork.Complete();
}
我必须清除WindowsGroups和WindowsLogins的两个列表才能正确更新联结表,现在可以使用。但是,只要我分配新的WindowsGroups或WindowsLogins列表,Entity Framework就会插入重复的WindowsGroups或WindowsLogins。联结表使用新的Id更新,因此它在应用程序中看起来正确,但在数据库中却是错误的。
我愿意接受任何建议和反馈。提前谢谢!
答案 0 :(得分:0)
进一步了解实体框架对实体所做的更改跟踪,我找到了解决问题的方法。我更改了我的更新语句如下:
public void Update(BusinessUnit businessUnit)
{
var oldBusinessUnit = _unitOfWork.BusinessUnits.GetById(businessUnit.Id);
oldBusinessUnit.Name = businessUnit.Name;
oldBusinessUnit.WindowsGroups.Clear();
oldBusinessUnit.WindowsLogins.Clear();
if (businessUnit.WindowsGroups != null)
{
var windowsGroupIds = businessUnit.WindowsGroups.Select(x => x.Id).ToList();
foreach (var winGroup in _unitOfWork.WindowsGroups.Find(winGroup => windowsGroupIds.Contains(winGroup.Id)).ToList())
{
oldBusinessUnit.WindowsGroups.Add(_unitOfWork.WindowsGroups.GetById(winGroup.Id));
}
}
if (businessUnit.WindowsLogins != null)
{
var windowsLoginIds = businessUnit.WindowsLogins.Select(x => x.Id).ToList();
foreach (var winLogin in _unitOfWork.WindowsLogins.Find(winLogin => windowsLoginIds.Contains(winLogin.Id)).ToList())
{
oldBusinessUnit.WindowsLogins.Add(_unitOfWork.WindowsLogins.GetById(winLogin.Id));
}
}
_unitOfWork.Complete();
}
我首先检查两个列表是否实际包含某些内容。然后我遍历从我的视图中返回的列表,并使用Id来直接从我的上下文中获取实体(通过UoW)。我不知道它是否是最佳解决方案,但它确实有效。