我有更新有多对多关系的网友的问题。在我的用户和类别下面:
public class User : IEntity
{
[Key]
public virtual long Id { get; set; }
private ICollection<Category> _availableCategories;
public virtual ICollection<Category> AvailableCategories
{
get { return _availableCategories ?? (_availableCategories = new List<Category>()); }
set { _availableCategories = value; }
}
}
public class Category : IEntity
{
[Key]
public long Id { get; set; }
/// <summary>
/// Full name or description of a category
/// </summary>
[StringLength(255)]
public string FullName { get; set; }
}
这是我的资源库中的代码段
public override void Edit(User user)
{
var dbUser = _context.Users.Include(x => x.AvailableCategories)
.Single(x => x.Id == user.Id);
var categories = _context.Categories;
dbUser.AvailableCategories.Clear();
foreach (var cat in user.AvailableCategories)
{
dbUser.AvailableCategories.Add(cat);
}
_context.Entry(dbUser).State = EntityState.Modified;
}
但是类别不会更新。 EF做的是将空行插入类别表,并使用user设置与这些新行的关系。
如何更新用户以便仅更改数据库中已存在的类别?
我传递给Edit方法的用户拥有只设置了ID的AvailableCategories(其余属性为空)。
答案 0 :(得分:0)
我注意到您还将user.AvailableCategories直接添加到dbUser.AvailableCategories中。我注意到,当从MVC视图绑定复杂对象时,DB实体不再附加到DbContext。如果查看实体,可以通过检查dbContext.Entry(cat)验证。我认为.State是“分离的”(或意外的)。
您必须从dbContext中查询这些实体(可能使用返回的cat.Id)。或者以其他方式手动将实体设置为“未更改”。然后将这些“非分离”项添加到dbUser.AvailableCategories中。请参阅Chris的回答,因为它显示了具体代码如何完成这项工作。
另外,我可能会使用链接实体。可能是这样的:
public class UserCategory
{
public User User {get;set;}
public Category Category {get;set;}
}
并将其添加到DB上下文中。此外,删除当前用户和类别类中的链接列表。这样,您可以操纵UserCategory类(和DbSet)来管理您的多对多关系。
答案 1 :(得分:0)
当您执行回发M2M关系之类的操作时,您必须发布完整对象,就像在这些对象上的每个属性中一样,或者只是发布一个id列表然后使用它们从数据库中查询关联的对象。否则,Entity Framework也会理解您更新对象属性的目的,在这种情况下为空值。
显然第一种选择非常笨重,所以第二种方式是首选和标准方式。通常,为此,您需要使用视图模型,这样您就可以拥有如下所示的属性:
public List<long> SelectedCategories { get; set; }
但是,如果您坚持直接使用该实体,只需执行以下操作即可获得相同的结果:
var selectedCategories = user.AvailableCategories.Select(m => m.Id)
一旦你有了ids:
var newAvailableCategories = _context.Categories.Where(m => selectedCategories.Contains(m.Id));
然后最终在您的用户上设置:
dbUser.AvailableCategories = newAvailableCategories;