1

假设我有一个名为MyItem的实体。它可以包含在许多“父母”中,如SomeCollection和SomeOtherCollection。因为它可以包含在许多父母中,并且由于我不希望MyItem知道父母,所以我想在MyItem中引用父母时没有任何属性。NHibernate实体松耦合

而且,像SomeCollection一样,父母可以包含许多MyItems,我觉得我需要某种分页方式来从父母中获取孩子。这会让我无法在SomeCollection中引用MyItems中的属性。懒惰加载或不加载,它总是“全部或全部”(对吧?)。

我绝对需要一些引用MyItem实体和他们的父母,虽然在数据库中的映射表的形式。

问题:

  • 如何创建此映射? 我可以有映射,还是应该将 关系保留在业务逻辑 中?
  • 如何查询 哪些MyItem实体存在于 SomeCollection?我可以使用ICriteria只进行一次数据库访问吗?
+0

伟大的问题。很棒,正是我想问的。 – Slavo

回答

1

Many-to-One
家长包含物业孩子,孩子可以从几个家长联系起来。

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

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

Many-to-Many with a join table
家长包含的子集,孩子们可以从几个家长联系起来。

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> 

Criteria Querying

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

这最后的查询可能会或可能不会被更有效地利用只是延迟加载上首次访问整个儿集合,然后索引到它后来的“做页面”。这取决于您的数据和使用情况。

除非我先知道孩子的收藏会是巨大的,否则我会首先进入懒惰的负载路线。如果时间和profiling显示严重缓慢,那么我会切换到标准方法。

+0

这是我如何解释你有关分页的答案: 如果我将懒加载设置为false,我不会使用父级的属性,而是执行像“页面”之类的条件来获取父级的子级页面。 另一种方法是对批量大小使用延迟加载。然后,如果我使用Children属性,则会一次提取“批量”孩子。因此,对于批次数为20的孩子,如果孩子数量为41到60,则会导致三次到数据库,每次导致20个项目。 这是对你答案的正确解释吗? – Kristoffer

+0

@Kristoffer使用lazy =“true”,如果你不想让孩子加载Parent。 –

+0

@Kristoffer我刚刚运行了一些测试,并且我的建议对于批处理大小和集合是错误的。答案已经相应更新。 –

0

我有像你这样的情况。我有配置类,可以是全局配置,项目特定配置或用户特定配置。我所做的是这样的:

  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> 
  • 我的配置作为集合映射在每一个可能的父母
  • < 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> 
    

    就像那样,它对我有用。如何访问配置,例如,用户ID为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,甚至可以删除集合映射。

    注意:我在NHibernate的早期阶段使用过Criteria,但后来我发现HQL对我来说有点强大,其他人可能会对此有不同的看法。