2011-03-22 195 views
4

我有两个类:实体框架 - 代码先保存多对多关系

public class Company 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

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

public class User 
{ 
    public int Id { get; set; } 
    public string Email { get; set; } 

    public virtual ICollection<Company> Companies { get; set; } 
} 

在我的MVC应用程序控制器从后得到新的公司。我想将当前用户添加到创建的公司中。

User user = GetCurrentLoggedUser(); 
//company.Users = new ICollection<User>(); // Users is null :/ 
company.Users.Add(user); // NullReferenceException 
companyRepository.InsertOrUpdate(company); 
companyRepository.Save(); 

它应该看起来应该如何正常工作?我还不知道它,但添加用户到集合后,我希望保存到数据库的问题。任何有关它应该是什么样的提示将不胜感激。

回答

6

使用这种方法:

public class Company 
{ 
    public int Id { get; set; } 
    public string Name { get; set;} 

    private ICollection<User> _users; 
    public ICollection<User> Users 
    { 
     get 
     { 
      return _users ?? (_users = new HashSet<User>()); 
     } 
     set 
     { 
      _users = value; 
     } 
    } 
} 

HashSet是优于其他收藏品,如果你也覆盖你的实体EqualsGetHashCode。它会为你处理复杂性。懒惰集合初始化更好。我不记得它,但我认为我在我的第一个EF测试应用程序中有一些问题,当我在构造函数中初始化集合并且还使用动态代理进行延迟加载和更改跟踪时。

有两种类型的实体:detached和attached。一个附属实体已经被上下文跟踪。您通常会从linq-to-entities查询中获取附加的实体,或者拨打DbSet,致电Create。一个分离的实体不被上下文跟踪,但是一旦你在该集上调用AttachAdd来附加该实体,所有相关实体也将被附加/添加。处理分离的实体时唯一需要处理的问题是相关实体是否已经存在于数据库中,而您只想创建新的关系。

,你必须了解的主要规则是添加和连接方法之间的差异:

  • Add将连接所有分离的实体在图形作为Added =>所有相关实体将被插入新的。
  • Attach会将图中所有分离的实体附加为Unchanged =>您必须手动说出已修改的内容。

您可以通过手动设置连接的任何实体的状态:

context.Entry<TEntity>(entity).State = EntityState....; 

当分离多到很多,通常你必须使用这些技术来构建,而不是插入duplicit实体只关系工作数据库。

根据我自己的经验,处理分离的实体图非常困难,尤其是在删除关系之后,因此我总是从数据库加载实体图并手动将更改合并到附加图中,以便能够完全跟踪所有更改。

请注意,您不能混合来自不同上下文的实体。如果你想将实体从一个上下文连接到另一个上下文,你必须首先明确地将实体从第一个实体中分离出来。我希望你可以通过在第一个上下文中将其状态设置为Detached来实现。

+0

在这一刻我看不到HashSet和Collection之间有很大的区别(我选择HashSet)。你帮助我理解如何管理我的上下文。在获取用户之前,我将CompanyRepository的上下文设置为UserRepository。这给我快速的工作解决方案。非常感谢。 – bizon 2011-03-22 23:08:36

2

在公司实体的构造函数中,您可以在Users属性上创建一个空集合。

public class Company 
{ 
    public Company() { 
     Users = new Collection<User>(); 
    } 

    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<User> Users { get; set; } 
} 

至于保存到数据库而言,我问了一个相关的问题,前几天,并得到保证实体框架能够追踪到相关实体所做的更改。阅读上,在这里:

Are child entities automatically tracked when added to a parent?

+0

感谢您的回答。当我添加从不同的存储库(和不同的上下文)加载的用户时,我得到错误:'一个实体对象不能被多个IEntityChangeTracker实例引用。改变后就像你的问题。一切正常,但它会在数据库中创建另一个用户,并且不使用给定的ID。 User user = new UserRepository()。GetByEmail(User.Identity.Name); \t \t \t \t company.Users.Add(新用户{Id = user.Id,FirstName = user.FirstName,LastName = user.LastName,Email = user.Email}); \t \t \t \t companyRepository.InsertOrUpdate(company); \t \t \t \t companyRepository.Save(); – bizon 2011-03-22 22:35:46