NHibernate отображения, когда отношения самосоединения имеют дополнительные свойства
Как вы сопоставляете класс с другими экземплярами того же класса , когда это отношение само имеет свойства?
У меня есть класс 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. Однако это не объясняет, что делать, когда это самосоединение. Разница в том, что если я попрошу всех связанных людей Dave Dee (ID = 1), я не только должен получить Tich (ID = 5), но я должен также получить Dozy (ID = 2), потому что Dave Dee также находится в 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;
}
}
И иметь в гбм следующее:
<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 обычно есть элегантные решения большинства повседневных проблем. Является ли вышеизложенное разумным способом сделать это или есть лучший способ?2 ответа:
Я думаю, что сделал бы это так же, но, я думаю, что это немного "неуклюже", чтобы смоделировать это так. Я имею в виду: у вас есть коллекция лиц, с которыми связан определенный человек, но у вас также есть "обратная связь".
Это действительно необходимо ? Не является ли это возможностью удалить эту обратную коллекцию и вместо этого указать метод на PersonRepository, который может вернуть вам всех людей, которые имеют какое-то отношение к данному человеку ?Хм, это может звучать немного непонятно, поэтому вот вам какой-то код (заметьте, что для краткости я опустил "виртуальные" модификаторы и т. д... (Я также предпочитаю не иметь этих модификаторов, поэтому в 99% случаев я указываю 'lazy=false' в своем отображении класса).
Как вы можете видеть, у класса Person осталась только одна коллекция, то есть коллекция объектов PersonPerson, представляющая отношения, которые имеет этот человек. Для того чтобы получить людей, которые имеют отношения с данным человеком, вы можете создать определенный метод на вашем PersonRepository, который возвращает эти лица, вместо того, чтобы иметь их в коллекции на Person class. Я думаю, что это также улучшит производительность.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 ) { ... } }
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(); } }
'back-reference' не является членом класса Person; доступ к нему должен осуществляться через репозиторий. Это также то, что говорит Эрик Эванс в своей DDD - книге: в некоторых случаях лучше иметь специализированный метод в репозитории, который может дать вам доступ к связанным объектам, а не иметь их (= related объекты), чтобы носить с собой сам объект.
Я не тестировал код,я просто набрал его здесь, поэтому я также не проверял синтаксическую ошибку и т. д... но я думаю, что это должно немного прояснить, как я буду это видеть.
Мне кажется, что вы по существу построили модель направленного графа, и два отображения
Эта направленность усиливается семантикой ваших типов отношений: в то время как является коллегой , скорее всего, является симметричным отношением ., is-a-Manager-of и is-a-Tutor-of почти определенно асимметричны.PersonPersonForward
иPersonPersonBack
представляют исходящие и входящие ребра соответственно.Я думаю, что в этом случае модель данных пытается скажите вам, что две коллекции ссылок, хотя и совместимого типа, не являются одним и тем же в контексте.