流畅的NHibernate:映射复杂的多对多(带有附加列)和设置提取

Hac*_*ese 5 .net nhibernate many-to-many nhibernate-mapping fluent-nhibernate

我需要一个Fluent NHibernate映射来完成以下操作(如果没有别的,我还将采用适当的NHibernate XML映射并对其进行反向工程).


细节

我在两个实体之间有多对多的关系:ParentChild.这是通过附加表来完成的,用于存储父母和孩子的身份.但是,我还需要在该映射上定义两个附加列,以提供有关该关系的更多信息.

这大致是我如何定义我的类型,至少是相关部分(其中Entity一些基类型提供Id属性并基于该Id检查等价):

public class Parent : Entity
{
    public virtual IList<ParentChildRelationship> Children { get; protected set; }

    public virtual void AddChildRelationship(Child child, int customerId)
    {
       var relationship = new ParentChildRelationship
                        {
                           CustomerId = customerId,
                           Parent = this,
                           Child = child
                        };
       if (Children == null) Children = new List<ParentChildRelationship>();
       if (Children.Contains(relationship)) return;
       relationship.Sequence = Children.Count;
       Children.Add(relationship);
    }
}

public class Child : Entity
{
    // child doesn't care about its relationships
}

public class ParentChildRelationship
{
    public int CustomerId { get; set; }
    public Parent Parent { get; set; }
    public Child Child { get; set; }
    public int Sequence { get; set; }

    public override bool Equals(object obj)
    {
       if (ReferenceEquals(null, obj)) return false;
       if (ReferenceEquals(this, obj)) return true;
       var other = obj as ParentChildRelationship;
       if (return other == null) return false;

       return (CustomerId == other.CustomerId
           && Parent == other.Parent
           && Child == other.Child);
    }

    public override int GetHashCode()
    {
       unchecked
       {
           int result = CustomerId;
           result = Parent == null ? 0 : (result*397) ^ Parent.GetHashCode();
           result = Child == null ? 0 : (result*397) ^ Child.GetHashCode();
           return result;
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

数据库中的表看起来大致相似(假设主键/外键和原谅语法):

create table Parent (
   id int identity(1,1) not null
)

create table Child (
   id int identity(1,1) not null
)

create table ParentChildRelationship (
   customerId int not null,
   parent_id int not null,
   child_id int not null,
   sequence int not null
)
Run Code Online (Sandbox Code Playgroud)

我很好,Parent.Children是一个懒惰的加载属性.但是,ParentChildRelationship应该急于加载ParentChildRelationship.Child.此外,我希望在我急切加载时使用加入.

SQL,当访问Parent.Children时,NHibernate应生成一个等效的查询:

SELECT * FROM ParentChildRelationship rel LEFT OUTER JOIN Child ch ON rel.child_id = ch.id WHERE parent_id = ?

好的,所以要做到这一点我有这样的映射:

ParentMap : ClassMap<Parent>
{
   public ParentMap()
   {
      Table("Parent");
      Id(c => c.Id).GeneratedBy.Identity();
      HasMany(c => c.Children).KeyColumn("parent_id");
    }
}

ChildMap : ClassMap<Child>
{
   public ChildMap()
   {
      Table("Child");
      Id(c => c.Id).GeneratedBy.Identity();
   }
}


ParentChildRelationshipMap : ClassMap<ParentChildRelationship>
{
   public ParentChildRelationshipMap()
   {
      Table("ParentChildRelationship");
      CompositeId()
                .KeyProperty(c => c.CustomerId, "customerId")
                .KeyReference(c => c.Parent, "parent_id")
                .KeyReference(c => c.Child, "child_id");
      Map(c => c.Sequence).Not.Nullable();
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,在我的测试中,如果我试图获得myParentRepo.Get(1).Children,它实际上确实得到了我所有的关系,并且当我从关系中访问它们时,Child对象(例如,我可以通过这样做抓住它们parent.Children.Select(r => r.Child).ToList()).

但是,NHibernate生成的SQL效率低下.当我访问parent.Children时,NHIbernate会为每个关系中的每个孩子执行a SELECT * FROM ParentChildRelationship WHERE parent_id = 1和a SELECT * FROM Child WHERE id = ?.我理解为什么NHibernate会这样做,但我无法弄清楚如何设置映射以按照我上面提到的方式进行NHibernate查询.

Ste*_*ger 2

我不明白为什么它不能按照你的方式工作,但我可以告诉你我将如何映射它:

<class name="Parent">

    <id .../>

    <list name="Children" table="ParentChildRelationship">
        <key column="parent_id"/>
        <index column="Sequence"/>

        <composite-element>
            <property name="CustomerId"/>
            <many-to-one name="Child"/>
        </composite-element>
    </list>

</class>

<class name="Child">
    <id .../>
    <property .../>
</class>
Run Code Online (Sandbox Code Playgroud)

为了提高性能,尝试让它通过连接获取多对一:

      <many-to-one name="Child" fetch="join" />
Run Code Online (Sandbox Code Playgroud)