NHibernate сопоставления, когда отношения самосоединения обладают дополнительными свойствами

StackOverflow https://stackoverflow.com/questions/606330

Вопрос

Как вы сопоставляете класс с другими экземплярами того же класса когда это отношение само по себе обладает свойствами?

У меня есть класс под названием Person, который сопоставлен таблице Person

PersonID   PersonName    PersonAge 
----------------------------------
       1   Dave Dee             55
       2   Dozy                 52
       3   Beaky                45
       4   Mick                 55
       5   Tich                 58

Я хочу, чтобы между человеком и персоной было отношение "многие ко многим", использующее таблицу соединений под названием PersonPerson:

 PersonPersonID  PersonID  RelatedPersonID RelationshipID 
 --------------------------------------------------------
              1         1                5              1
              2         3                4              2
              3         2                1              3

Мне нужны следующие атрибуты в таблице PersonPerson:

RelationshipID  RelationshipName
--------------------------------
             1  Colleague
             2  Manager
             3  Tutor

Этот вопрос и связанный с сообщение Билли Маккафферти объясняет, что отношение PersonPerson должно быть переведено из обычного ОБЪЕДИНЕНИЯ в самостоятельную сущность из-за дополнительных столбцов в таблице PersonPerson.Однако это не объясняет, что делать, когда это самосоединение.Разница в том, что если я попрошу всех связанных с этим людей Дэйв Ди (ID = 1), я не только должен получить Тич (ID = 5), но я должен получить также get Сонный (ID = 2) а также потому, что Дэйв Ди также находится в столбце RelatedPersonID.

Пока что мое решение заключается в том, чтобы иметь два свойства в моем классе Person.

public virtual IList<PersonPerson> PersonPersonForward {get;set;}
public virtual IList<PersonPerson> PersonPersonBack {get;set;}

private List<PersonPerson> personPersonAll;
public virtual List<PersonPerson> PersonPersonAll 
{
   get
   {
       personPersonAll = new List<PersonPerson>(PersonPersonForward);
       personPersonAll.AddRange(PersonPersonBack);
       return personPersonAll;
   }
}

И иметь следующее в hbm:

 <bag name="PersonPersonForward" table="PersonPerson" cascade="all">
      <key column="PersonID"/>
      <one-to-many class="PersonPerson" />
 </bag>

 <bag name="PersonPersonBack" table="PersonPerson" cascade="all">
      <key column="RelatedPersonID"/>
      <one-to-many class="PersonPerson" />
 </bag>

Это кажется немного неуклюжим и неэлегантным.NHibernate обычно предлагает элегантные решения большинства повседневных проблем.Является ли приведенное выше разумным способом сделать это или есть способ получше?

Это было полезно?

Решение

Я думаю, что я бы тоже сделал это таким образом, но, по-моему, это немного "неуклюже" моделировать это таким образом.Я имею в виду:у вас есть набор людей, с которыми связан определенный человек, но у вас также есть "обратная связь".
Действительно ли это необходимо ?Разве это не вариант удалить эту обратную коллекцию и вместо этого указать метод в PersonRepository, который может вернуть вам всех пользователей, которые имеют какое-то отношение к данному человеку?

Хм, возможно, это звучит немного непонятно, поэтому вот немного кода (обратите внимание, что для краткости я опустил "виртуальные" модификаторы и т.д...(Я также предпочитаю не использовать эти модификаторы, поэтому в 99% случаев я указываю 'lazy = false' при сопоставлении классов).

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

    public IList<PersonPerson> _relatedPersons;

    public ReadOnlyCollection<PersonPerson> RelatedPersons
    {
        get
        {
           // The RelatedPersons property is mapped with NHibernate, but
           // using its backed field _relatedPersons (can be done using the 
           // access attrib in the HBM.
           // I prefer to expose the collection itself as a readonlycollection
           // to the client, so that RelatedPersons have to be added through
           // the AddRelatedPerson method (and removed via a RemoveRelatedPerson method).

           return new List<PersonPerson) (_relatedPersons).AsReadOnly();
        }
    }

    public void AddRelatedPerson( Person p, RelationType relatesAs )
    {
       ...
    }

}

Как вы можете видеть, у класса Person осталась только одна коллекция, то есть коллекция объектов PersonPerson, которая представляет отношения, имеющиеся у этого Person.Чтобы получить людей, которые имеют отношения к данному человеку, вы могли бы создать определенный метод в вашем PersonRepository, который возвращает этих людей, вместо того, чтобы иметь их в коллекции в классе Person.Я думаю, что это также улучшит производительность.

public class NHPersonRepository : IPersonRepository
{
    ...

    public IList<Person> FindPersonsThatHaveARelationShipWithPerson( Person p )
    {
        ICriteria crit = _session.CreateCriteria <Person>();

        crit.AddAlias ("RelatedPersons", "r");

        crit.Add (Expression.Eq ("r.RelatedWithPerson", p));

        return crit.List();

    }
}

"Обратная ссылка" не является членом класса Person;доступ к нему должен быть предоставлен через репозиторий.Это также то , что говорит Эрик Эванс в своей DDD - книге:в некоторых случаях лучше иметь специализированный метод в репозитории, который может предоставить вам доступ к связанным объектам, вместо того, чтобы переносить их (= связанные объекты) с самим объектом.

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

Другие советы

Мне кажется, что вы, по сути, построили модель ориентированный граф, и два сопоставления PersonPersonForward и PersonPersonBack представляют собой исходящие и входящие ребра соответственно.

Эта направленность усиливается семантикой ваших типов отношений:в то время как является-Коллегой-из скорее всего, это симметричное отношение, является менеджером и является-наставником- почти определенно асимметричны.

Я думаю, что в данном случае модель данных пытается сказать вам, что две коллекции ссылок, хотя и имеют совместимый тип, не являются одним и тем же в контексте.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top