Entity Framework - Code First сохраняет отношения многих ко многим - PullRequest
4 голосов
/ 23 марта 2011

У меня есть два класса:

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

Как это должно выглядеть для правильной работы?Я еще не знаю, но после добавления пользователя в коллекцию, я ожидаю проблем с сохранением в базу данных.Любые советы о том, как это должно выглядеть, приветствуются.

Ответы [ 2 ]

6 голосов
/ 23 марта 2011

Используйте этот подход:

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 лучше, чем другие коллекции, если вы также переопределяете Equals и GetHashCode в своих сущностях. Он будет обрабатывать дубликаты для вас. Также ленивая инициализация коллекции лучше. Я точно не помню, но думаю, что у меня были некоторые проблемы в одном из моих первых тестовых приложений EF, когда я инициализировал коллекцию в конструкторе, а также использовал динамические прокси для отложенной загрузки и отслеживания изменений.

Существует два типа сущностей: отдельные и прикрепленные. Прикрепленный объект уже отслеживается контекстом. Вы обычно получаете присоединенную сущность из запроса linq-to-entity или вызывая Create на DbSet. Отделенная сущность не отслеживается контекстом, но как только вы вызовете Attach или Add в наборе для присоединения этой сущности, все связанные сущности также будут присоединены / добавлены. Единственная проблема, с которой вам приходится сталкиваться при работе с отсоединенными сущностями, это если связанная сущность уже существует в базе данных, и вы хотите создать только новое отношение.

Главное правило, которое вы должны понимать, это разница между методом Add и Attach:

  • Add будет прикреплять все отключенные объекты на графике как Added => все связанные объекты будут вставляться как новые.
  • Attach прикрепит все отключенные объекты в графе как Unchanged => Вы должны вручную сказать, что было изменено.

Вы можете вручную установить состояние любой присоединенной сущности, используя:

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

При работе с отсоединенными многими ко многим вы, как правило, должны использовать эти методы для построения только отношений вместо вставки в базу данных дублированных сущностей.

По моему собственному опыту работать с отделенными графами сущностей очень сложно, особенно после удаления отношений, и поэтому я всегда загружаю графы сущностей из базы данных и вручную объединяю изменения в прикрепленные графы, которые в состоянии полностью отследить все изменения для меня.

Имейте в виду, что вы не можете смешивать сущности из разных контекстов. Если вы хотите присоединить сущность из одного контекста к другому, вы должны сначала явно отделить сущность от первого. Я надеюсь, что вы можете сделать это, установив его состояние на Detached в первом контексте.

2 голосов
/ 23 марта 2011

В вашем конструкторе для сущности 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; }
}

Что касается сохранения в базе данных, я задал связанный вопрос несколько дней назад ибыл уверен, что Entity Framework может отслеживать изменения, внесенные в связанные объекты.Читайте об этом здесь:

Отслеживаются ли дочерние объекты автоматически при добавлении к родителю?

...