使用Fluent NHibernate/NHibernate&;自动映射
我需要加载一个名为节点的复杂对象…其实并没有那么复杂…它看起来如下所示:- 节点引用了实体类型,该实体类型具有一对多的属性,而该属性又具有一对多的PorpertyListValue使用Fluent NHibernate/NHibernate&;自动映射,nhibernate,fluent-nhibernate,eager-loading,automapping,Nhibernate,Fluent Nhibernate,Eager Loading,Automapping,我需要加载一个名为节点的复杂对象…其实并没有那么复杂…它看起来如下所示:- 节点引用了实体类型,该实体类型具有一对多的属性,而该属性又具有一对多的PorpertyListValue public class Node { public virtual int Id { get; set; } public virtual string Name { get; set; }
public class Node
{
public virtual int Id
{
get;
set;
}
public virtual string Name
{
get;
set;
}
public virtual EntityType Etype
{
get;
set;
}
}
public class EntityType
{
public virtual int Id
{
get;
set;
}
public virtual string Name
{
get;
set;
}
public virtual IList<Property> Properties
{
get;
protected set;
}
public EntityType()
{
Properties = new List<Property>();
}
}
public class Property
{
public virtual int Id
{
get;
set;
}
public virtual string Name
{
get;
set;
}
public virtual EntityType EntityType
{
get;
set;
}
public virtual IList<PropertyListValue> ListValues
{
get;
protected set;
}
public virtual string DefaultValue
{
get;
set;
}
public Property()
{
ListValues = new List<PropertyListValue>();
}
}
public class PropertyListValue
{
public virtual int Id
{
get;
set;
}
public virtual Property Property
{
get;
set;
}
public virtual string Value
{
get;
set;
}
protected PropertyListValue()
{
}
}
或者使用NHibernate LINQ
Session.Linq<NodeType>()
.Expand( "Etype")
.Expand( "Etype.Properties" )
.Expand( "Etype.Properties.ListValues" )
Session.Linq()
.Expand(“Etype”)
.Expand(“Etype.Properties”)
.Expand(“Etype.Properties.ListValues”)
当我运行上述任何一个查询时,它们都会生成一个包含所有左侧外部联接的相同查询,这正是我所需要的。但是,由于某些原因,查询返回的IList没有加载到对象中。事实上,返回的节点数等于查询的行数,因此节点对象是重复的。此外,每个节点内的属性和ListValue也是重复的
因此,我想知道如何修改上述查询,以返回包含属性和列表值的所有唯一节点。每个映射都必须进行延迟加载 在节点映射中:
Map(x => x.EntityType).Not.LazyLoad();
在EnityType映射中:
Map(x => x.Properties).Not.LazyLoad();
等等
另外,请参阅一次快速加载
增加:
有关Sql N+1的其他信息:
我自己想出来的。关键是使用SetResultTransformer()传递distinctroentityResultTransformer的对象作为参数。因此,查询现在如下所示
Session.CreateCriteria(typeof (Node))
.SetFetchMode( "Etype", FetchMode.Join )
.SetFetchMode( "Etype.Properties", FetchMode.Join )
.SetFetchMode( "Etype.Properties.ListValues", FetchMode.Join )
.SetResultTransformer(new DistinctRootEntityResultTransformer());
我通过以下链接找到了问题的答案:
带有DistinctRootEntityResultTransformer的SetResultTransformer将仅适用于主对象,但IList集合将成倍增加。我最终得出如下结论:
HasMany(x => x.YourList).KeyColumn("ColumnName").Inverse().Not.LazyLoad().Fetch.Join()
只需确保像这样选择您的实体,以避免因连接而重复:
session.CreateCriteria(typeof(T)).SetResultTransformer(Transformers.DistinctRootEntity).List<T>();
session.CreateCriteria(typeof(T)).SetResultTransformer(Transformers.distinctroventy).List();
感谢Tim的响应,我不想在映射中设置.not.LazyLoad(),因为它将成为默认行为,在我的应用程序中,我有一个wcf服务,需要将数据传递给客户端,我想在一个查询中一次性加载所有数据,以避免SQL N+1场景()。应用程序的其余部分不需要加载。那么,你知道我该如何解决这个问题吗?我的理解是.Not.LazyLoad不能解决SQLN+1问题。在Hibernate profiler中,我注意到,尽管它一次加载了整个对象图,但它仍然会生成多个查询,每个引用都有一个查询/hasmany对象,这是我不想要的,因为我有大量的节点,其中包含大量的EntityType和属性,我不希望生成这些唯一的查询。NabeelI以为你想把它映射成那样。我添加了一个指向另一个问题的链接,该问题显示了在特定实例中的急切加载。我认为这将有助于您创建一个连接。如果不是这样,您可以考虑纠正存储过程并将其映射为命名查询。请参阅中的原始海报代码,以获取该示例。另外,请查看Hi Tim,谢谢您提供的信息。实际上,我在生成查询时没有问题。生成的查询与nHibernate探查器公开的查询一样正确。奇怪的是,返回的“我的对象”列表有重复项,并且返回列表中的每个根对象在子集合中都有一些奇怪的笛卡尔积混乱,具有同一实体的多个实例,但在使用DistinctRootEntityResultTransformer并用ICollection而不是IList替换子集合之后,它正按照我的预期工作。但我想知道这是否是正确的解决方案?在google上,我发现了DistincTrotentyResultTransformer,但这只解决了根对象的问题。我仍然在孩子们的收藏中得到重复。返回列表中的每个根对象在具有同一实体的多个实例的子集合中都有一些奇怪的笛卡尔积混乱。有什么想法吗?等待纳贝里的是,我想我已经找到了解决办法,但我想知道这是否正确。根对象(节点)内的子集合(EType.Properties、EType.Properties.ListValues)是IList。我在文档中读到,IList可以包含重复的实例,因此如果我将IList更改为ISet/ICollection,则查询不会在子集合中加载重复的实例。但是这个解决方案需要大量的重构。我想知道是否有一种方法可以使用IList实现同样的儿童收藏?等待,NabeelI也有同样的问题(使用Fetchmode.Eager)。我对这件事很失望。我宁愿有一个错误,也不愿有不正确的数据。+1,但哇,这太难看了。这看起来真是一团糟——我对Nibernate的这一点印象不深。为什么我们需要改变结果?NH似乎做得不好。您将如何使用ISet或ICollection?您也可以使用参考资料吗?
session.CreateCriteria(typeof(T)).SetResultTransformer(Transformers.DistinctRootEntity).List<T>();