NHibernate сущность слабой связи - PullRequest
1 голос
/ 04 марта 2010

Допустим, у меня есть объект под названием MyItem. Он может быть включен во многих «родителей», таких как SomeCollection и SomeOtherCollection. Поскольку это может быть включено во многих родителей, и поскольку я не хочу, чтобы MyItem знал о родителях, я бы не хотел, чтобы в MyItem были какие-либо свойства, ссылающиеся на родителя.

И так как родитель, например SomeCollection, может содержать много разных MyItems, я чувствую, что мне нужно что-то вроде подкачки, чтобы получить детей от родителя. Это не позволило бы мне иметь свойство в SomeCollection, ссылающееся на MyItems. Ленивый загружен или нет, это всегда "все или ничего" (верно?).

Мне определенно нужна некоторая ссылка между сущностями MyItem и их родителями, хотя бы в форме таблицы сопоставления в базе данных.

Вопросы:

  • Как мне создать сопоставления для этого? Могу ли я иметь сопоставления, или если отношения должны быть в бизнесе логика вместо?
  • Как бы я запросить какие объекты MyItem существуют в SomeCollection? Могу ли я сделать это только с одной поездкой в ​​базу данных с использованием ICriteria?

Ответы [ 2 ]

1 голос
/ 04 марта 2010

Много-к-One
Родитель содержит свойство Child, ребенок может быть связан с несколькими родителями.

class Parent
{
    public virtual MyItem Child { get; set; }
}

<class name="Parent">
    <many-to-one name="Child" column="MyItemId" />
</class>

Многие ко многим с таблицей соединений
Родитель содержит коллекцию Children, дети могут быть связаны от нескольких родителей.

class Parent
{
    public virtual IList<MyItem> Children { get; set; }
}

<class name="Parent">
    <bag name="Children" table="parent_myitem">
        <key column="parentid" />
        <many-to-many class="MyItem" column="MyItemId" />
    <bag>
</class>

Критерии запроса

// find Parent with child named "foo".
DetachedCriteria.For<Parent>()
    .CreateAlias("Child", "c")
    .Add(Restrictions.Eq("c.Name", "foo"));

// find Parent with particular child
DetachedCriteria.For<Parent>()
    .Add(Restrictions.Eq("Child", child ));


// find Parent with one of children named "foo".
DetachedCriteria.For<Parent>()
    .CreateAlias("Children", "c")
    .Add(Restrictions.Eq("c.Name", "foo"));

// find a "page" of children for a parent
DetachedCriteria.For<Parent>()
    .Add(Restrictions.Eq("Id", parent.Id ))
    .CreateAlias("Children", "c")
    .SetFirstResult( 1041 )
    .SetMaxResults( 20 )
    .GetExecutableCriteria( session )
    .List<MyItem>();

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

Если я априори не знал, что дочерние коллекции будут гигантскими, я сначала пошел бы по пути ленивой загрузки. Если тайминг и профилирование показывают серьезную медлительность, то я бы переключился на метод Критерии.

0 голосов
/ 05 марта 2010

У меня был такой же случай, как у тебя. У меня был класс конфигурации, который может быть либо глобальной конфигурацией, либо конкретной конфигурацией проекта, либо конкретной конфигурацией пользователя. Что я сделал, это было:

  1. Я сопоставляю Родителя, как обычно в любом случае, со всеми возможными родителями (кроме глобальных, это означает, что применяется ко всем, поэтому нет родителей)
< class name="ConfigurationDomain" table="configuration">  
    < property name="ProjectId" column="project_id" type="int" insert="false" update="false" />  
    < property name="UserId" column="user_id" type="int" insert="false" update="false" />  
    < many-to-one name="Project" column="project_id" lazy="false" />  
    < many-to-one name="User" column="estimator_id" lazy="false" />
< /class>  
  1. Я отображаю конфигурацию как коллекцию во всех возможных родителях
< class name="UserDomain" table="user">  
    < set name="ConfigurationList" lazy="true" cascade="all-delete-orphan">  
      < key column="user_id" />  
      < one-to-many class="ConfigurationDomain" />  
    < /set>  
< /class>  

< class name="ProjectDomain" table="user">  
    < set name="ConfigurationList" lazy="true" cascade="all-delete-orphan">  
      < key column="project_id" />  
      < one-to-many class="ConfigurationDomain" />  
    < /set>  
< /class>

Просто так, и это сработало для меня. Как мне получить доступ к конфигурации, скажем, пользователя с идентификатором 55 это:

Я не использую someUser.ConfigurationList, поскольку он работает медленно. Я только сопоставляю родителя, чтобы я мог сделать это на HQL (это намного быстрее):

select c from ConfigurationDomain c where c.UserId=55

И чтобы получить глобальную конфигурацию, я бы сделал это:

select c from ConfigurationDomain c where (c.UserId IS NULL) and (c.ProjectId IS NULL)

Если подумать, я думаю, что вы даже можете удалить отображение коллекции, если решите использовать HQL.

ПРИМЕЧАНИЕ: Я использовал Criteria в ранние годы с NHibernate, но потом я обнаружил, что HQL несколько более мощный для меня, другие могут иметь другое мнение по этому поводу.

...