实体框架 - 代码优先保存多对多关系

时间:2011-03-22 21:50:07

标签: c# asp.net-mvc-3 entity-framework-4 ef-code-first

我有两个班级:

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应用程序控制器中从post发送新公司。我希望将当前用户添加到创建的公司中。

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

如何正常工作?我还不知道但是在将用户添加到集合之后,我预计将其保存到数据库会出现问题。任何关于它应该是什么样子的提示都将不胜感激。

2 个答案:

答案 0 :(得分: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;
        }
    }
}
如果您还在实体中覆盖HashSetEquals,则

GetHashCode比其他集合更好。它将为您处理重复。懒惰的集合初始化也更好。我完全不记得了,但是当我在构造函数中初始化集合并且还使用动态代理进行延迟加载和更改跟踪时,我认为我的第一个EF测试应用程序中遇到了一些问题。

有两种类型的实体:分离和附加。上下文已跟踪附加实体。您通常从linq到实体查询或通过Create上的DbSet调用附加的实体。上下文实体不会被上下文跟踪,但是一旦您在集合上调用AttachAdd来附加此实体,所有相关实体也将被附加/添加。使用分离实体时,您必须处理的唯一问题是,如果相关实体已存在于数据库中,并且您只想创建新关系。

您必须了解的主要规则是添加和附加方法之间的区别:

  • Add会将所有已分离的实体附加到图表中Added =&gt;所有相关实体都将作为新实体插入。
  • Attach会将所有已分离的实体附加到图表中Unchanged =&gt;你必须手动说出修改过的内容。

您可以使用以下方法手动设置任何附加实体的状态:

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

使用分离的多对多数时,通常必须使用这些技术来构建关系,而不是将重复实体插入数据库。

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

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

答案 1 :(得分:2)

在Company实体的构造函数中,您可以在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?