Как смоделировать отношения «многие ко многим» с сущностью отношения в EF 4.1 Code First - PullRequest
0 голосов
/ 21 сентября 2011

Популярный пример: в системе отслеживания проблем JIRA проблемы могут быть связаны с другими проблемами.К самой ссылке прикреплены некоторые данные, в частности тип.

Пример:

Выпуск A -> зависит от -> Выпуск B Выпуск B <- <em>зависит от <- <strong>Выпуск A

Мы вводим такие же отношения для сущности в нашем C #Приложение ASP.NET MVC, использующее EF 4.1 CodeFirst, и мне интересно, как лучше всего смоделировать это отношение?


Подробности :

В этой ситуации есть некоторые особенности:

  • К ссылке прикреплены некоторые данные, поэтому мы не можем просто смоделировать отношения «многие ко многим» между проблемами и проблемами.Скорее, нам нужно ввести новую сущность Ссылка , которая представляет связь между двумя проблемами.
  • Ссылка, по определению, связывает два экземпляра одной и той же сущности,это отношение «два ко многим» (ссылка имеет две проблемы, проблема может иметь много ссылок).
  • Ссылка направлена, что означает, что если проблема A зависит от проблемы B, то проблема B зависит от проблемы A.

У нас наверняка будет сущность Link , которая выглядит следующим образом:

public class Link
{
    public int ID { get; set; }
    public Issue IssueA { get; set; }
    public Issue IssueB { get; set; }
    public LinkType Type { get; set; }
}

Класс Issue может выглядеть следующим образом:

public class Issue
{
    public int ID { get; set; }
    public virtual ICollection<Link> Links { get; set; }
}

В настоящее время существуетбыть только один тип ссылки: зависимость.Итак, тип ссылки будет выглядеть следующим образом:

public class LinkType
{
    public int ID { get; set; }
    public string ForwardName { get; set; } // depends on
    public string BackwardName { get; set; } // is depended on by
}

Теперь большой вопрос:

Если я хочу, чтобы EF автоматически управлял Issue.Links, у меня естьсказать ему, какой внешний ключ в таблице Link использовать.Либо я использую IssueA, либо я использую IssueB.Я не могу использовать оба, могу ли я?

Либо я определяю:

modelBuilder.Entity<Issue>().HasMany(i => i.Links).WithRequired(l => l.IssueA);

, либо я определяю:

modelBuilder.Entity<Issue>().HasMany(i => i.Links).WithRequired(l => l.IssueB);

Возможные подходы - Мне любопытно ваше мнение о том, могут ли некоторые из них привести к проблемам, не могут быть реализованы или какой-либо из этих подходов может рассматриваться как «наилучшая практика»:

  • Добавьте дваКоллекции к Выпуск , ICollection<Link> OutgoingLinks, ICollection<Link> IncomingLinks.Таким образом, EF может поддерживать коллекции, но с точки зрения бизнес-логики они не имеют особого смысла.
  • Добавьте только одну коллекцию и настройте EF 4.1 для добавления входящих и исходящие ссылки на него, если это возможно.
  • Добавьте только одну коллекцию и реализуйте ее самостоятельно:

    ICollection<Link> AllLinks { return _context.Links.Where(l => l.IssueA == this || l.IssueB == this).ToList(); }

    Проблема с этим подходомв том, что объект домена выполняет задачи доступа к данным, что плохо с точки зрения разделения проблем.

  • Любое другое?

1 Ответ

2 голосов
/ 21 сентября 2011

Вариант (1) - это, на мой взгляд, путь вместе с помощником только для чтения, который объединяет две коллекции:

public class Issue
{
    public int ID { get; set; }
    public virtual ICollection<Link> OutgoingLinks { get; set; }
    public virtual ICollection<Link> InComingLinks { get; set; }

    public IEnumerable<Link> Links // not mapped because readonly
    {
        get { return OutgoingLinks.Concat(InComingLinks); }
    }
}

Опция (2) невозможна, поскольку вы не можете сопоставить одно свойство навигации с двумя разными свойствами конца / навигации.

...