我需要一个Fluent NHibernate映射来实现以下功能(如果没有别的,我还会采用适当的NHibernate XML映射并对其进行反向工程)。
详情
我在两个实体之间存在多对多关系:Parent
和Child
。这是通过附加表来完成的,用于存储父母和孩子的身份。但是,我还需要在该映射上定义两个附加列,以提供有关该关系的更多信息。
这大致是我如何定义我的类型,至少是相关部分(其中Entity
是一些提供Id
属性的基类型,并根据该Id检查等价性): / p>
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;
}
}
}
数据库中的表看起来大致相似(假设主键/外键和原谅语法):
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
)
我很好,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();
}
}
所以,在我的测试中,如果我试图获得myParentRepo.Get(1).Children
,它实际上确实得到了我所有的关系,当我从关系中访问它们时,Child对象(例如,我可以抓住它们通过parent.Children.Select(r => r.Child).ToList()
)。
但是,NHibernate生成的SQL效率低下。当我访问parent.Children时,NHIbernate为每个关系中的每个孩子执行SELECT * FROM ParentChildRelationship WHERE parent_id = 1
然后SELECT * FROM Child WHERE id = ?
。我理解为什么NHibernate会这样做,但我无法弄清楚如何设置映射以按照我上面提到的方式进行NHibernate查询。
答案 0 :(得分: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>
要提高性能,请尝试通过连接获取多对一:
<many-to-one name="Child" fetch="join" />