C# EF:使用添加、删除或未更改的子实体更新实体(多对多关系)
这是我第一次在asp.net mvc应用程序中使用EF。在过去的两天里,我阅读了类似的问题和例子,但到目前为止,我还没有完全理解我必须做什么 我有两个具有多对多关系的实体 型号:C# EF:使用添加、删除或未更改的子实体更新实体(多对多关系),c#,entity-framework,many-to-many,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; }
[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; }
}
我需要更新我的UserDepartments表(请参见上面的model builder),以便删除删除的、添加新的和保留特定用户的现有部门单位。上述操作不起作用,我迷路了,非常感谢您的帮助。只要将
dataContext
变量生存时间限定为单个UpdateUser
操作,您就可以让EF change tracker通过从数据库加载目标实体(包括相关集合)为您完成大部分工作,然后简单地将其替换为从传递实体的相应集合创建的存根实体列表:
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目前需要更多与您尝试过的类似的手动操作。工作代码:
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");
FWIW,此行:
this.dataContext.Entry(dbEntity).CurrentValues.SetValues(entity)代码>引发实体处于不同上下文中的异常。此行:dbEntity.DepartmentUnits=entity.DepartmentUnits.Select(e=>newunitentity{Id=e.Id}).ToList()代码>使用空值向Unit表中添加新行,并使用实际不存在的UnitId向UserDepartments表中添加条目。然而,你解决了我的问题,因为你让我用另一种方式思考。非常感谢,我将把我的工作方案放在下面。
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");
}
}
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();
}
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");