实体框架 - Code First 保存多对多关系

发布于 2024-10-26 13:12:23 字数 748 浏览 2 评论 0原文

我有两个类:

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();

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

I have two classes:

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; }
}

In my MVC application controller get new Company from post. I want to add current user to created Company in something like this.

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

How it should look like to work properly? I don't know it yet but after adding user to collection I expect problems with saving it to database. Any tips on how it should look like would be appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

抽个烟儿 2024-11-02 13:12:44

在 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; }
}

就保存到数据库而言,我几天前问了一个相关问题,并确信实体框架能够跟踪对相关实体所做的更改。在这里阅读:

在以下情况下是否自动跟踪子实体添加到父级?

In your constructor for the Company entity you can create an empty collection on the Users property.

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; }
}

As far as saving to the database is concerned, I asked a related question a few days ago and was assured that Entity Framework is able to track the changes made to related entities. Read up on that here:

Are child entities automatically tracked when added to a parent?

哀由 2024-11-02 13:12:42

使用此方法:

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;
        }
    }
}

如果您还重写实体中的 EqualsGetHashCode,则 HashSet 比其他集合更好。它会为你处理口是心非的事情。惰性集合初始化也更好。我记不太清楚了,但我认为当我在构造函数中初始化集合并使用动态代理进行延迟加载和更改跟踪时,我在第一个 EF 测试应用程序中遇到了一些问题。

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

您必须了解的主要规则是 Add 和 Attach 方法之间的区别:

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

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

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

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

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

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

Use this approach:

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 is better then other collections if you also override Equals and GetHashCode in your entities. It will handle duplicities for you. Also lazy collection initialization is better. I don't remember it exactly, but I think I had some problems in one of my first EF test applications when I initialized the collection in the constructor and also used dynamic proxies for lazy loading and change tracking.

There are two types of entities: detached and attached. An attached entity is already tracked by the context. You usually get the attached entity from linq-to-entities query or by calling Create on DbSet. A detached entity is not tracked by context but once you call Attach or Add on the set to attach this entity all related entities will be attached / added as well. The only problem you have to deal with when working with detached entities is if related entity already exists in database and you only want to create new relation.

The main rule which you must understand is difference between Add and Attach method:

  • Add will attach all detached entities in graph as Added => all related entities will be inserted as new ones.
  • Attach will attach all detached entities in graph as Unchanged => you must manually say what has been modified.

You can manually set state of any attached entity by using:

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

When working with detached many-to-many you usually must use these techniques to build only relations instead of inserting duplicit entities to database.

By my own experience working with detached entity graphs is very hard especially after deleting relations and because of that I always load entity graphs from database and manually merge changes into attached graphs wich are able to fully track all changes for me.

Be aware that you can't mix entities from different contexts. If you want to attach entity from one context to another you must first explicitly detach entity from the first one. I hope you can do it by setting its state to Detached in the first context.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文