使用 Fluent NHibernate/Nhibernate 进行预加载自动映射
我需要加载一个名为 Node 的复杂对象...好吧,它并不那么复杂...它看起来如下:-
Node 具有对 Node 的引用>EntityType 与 Property 存在一对多,而 PropertyType 又与 PorpertyListValue 存在一对多 strong>
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()
{
}
}
我试图做的是一次性加载 Node 对象和所有子对象。无延迟加载。原因是我的数据库中有数千个 Node 对象,我必须使用 WCF 服务通过网络发送它们。我遇到了 SQL N+ 1 类问题。我正在使用 Fluent Nhibernate 和 Automapping,NHibernate Profiler 建议我使用 FetchMode.Eager 一次性加载整个对象。我正在使用以下 qyuery
Session.CreateCriteria(typeof (Node))
.SetFetchMode( "Etype", FetchMode.Join )
.SetFetchMode( "Etype.Properties", FetchMode.Join )
.SetFetchMode( "Etype.Properties.ListValues", FetchMode.Join )
或使用 NHibernate LINQ
Session.Linq<NodeType>()
.Expand( "Etype")
.Expand( "Etype.Properties" )
.Expand( "Etype.Properties.ListValues" )
当我运行上述任何查询时,它们都会生成一个带有所有左外连接的相同单个查询,这就是我所需要的。但是,由于某种原因,查询返回的 IList 属性未加载到对象中。事实上,返回的 Nodes 计数等于查询的行数,因此 Nodes 对象是重复的。此外,每个 Node 内的属性是重复的,Listvalues 也是重复的。
所以我想知道如何修改上面的查询以返回所有具有属性和列表值的唯一节点。
I have a requirement to load a complex object called Node...well its not that complex...it looks like follows:-
A Node has a reference to EntityType which has a one to many with Property which in turn has a one to many with PorpertyListValue
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()
{
}
}
What I a trying to do is load the Node object with all the child objects all at once. No Lazy load. The reason is I have thousands of Node objects in the database and I have to send them over the wire using WCF Service.I ran into the classes SQL N+ 1 problem. I am using Fluent Nhibernate with Automapping and NHibernate Profiler suggested me to use FetchMode.Eager to load the whole objects at once. I am using the following qyuery
Session.CreateCriteria(typeof (Node))
.SetFetchMode( "Etype", FetchMode.Join )
.SetFetchMode( "Etype.Properties", FetchMode.Join )
.SetFetchMode( "Etype.Properties.ListValues", FetchMode.Join )
OR using NHibernate LINQ
Session.Linq<NodeType>()
.Expand( "Etype")
.Expand( "Etype.Properties" )
.Expand( "Etype.Properties.ListValues" )
When I run any of the above query, they both generate one same single query with all the left outer joins, which is what I need. However, for some reason the return IList from the query is not being loaded property into the objects. Infact the returned Nodes count is equal to the number of rows of the query, so the Nodes objects are repeated.Moreover, the properties within each Node are repeated, and so do the Listvalues.
So I would like to know how to modify the above query to return all unique Nodes with the properties and list values within them.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
带有 DistinctRootEntityResultTransformer 的 SetResultTransformer 仅适用于 Main 对象,但 IList 集合将成倍增加。
SetResultTransformer with DistinctRootEntityResultTransformer will only work for Main object but IList collections will be multiplied.
我最终得到了这样的结果:
只需确保像这样选择您的实体,以避免由于连接而重复:
I ended up with something like this:
Just make sure to select your entity like this, to avoid duplication due to the join:
我自己想办法。关键是使用 SetResultTransformer() 传递 DistinctRootEntityResultTransformer 的对象作为参数。因此,查询现在如下所示,
我通过这些链接找到了问题的答案:
http://www.mailinglistarchive.com/html/[电子邮件受保护]/2010-05/msg00512.html
http ://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx
I figure it out myself. The key is to use SetResultTransformer() passing an object of DistinctRootEntityResultTransformer as a parameter. So the query now looks like as follows
I found the answer to my questions through these links:
http://www.mailinglistarchive.com/html/[email protected]/2010-05/msg00512.html
http://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx
每个映射都必须
在 Node Map:
在 EnityType Map:
等中关闭延迟加载...
另外,请参阅 NHibernate 急切加载多级子对象一次急切加载
添加:
有关 Sql N+1 的其他信息:
http://nhprof.com/Learn/Alerts/SelectNPlusOne
each mapping has to have lazy loading off
in Node Map:
in EnityType Map:
and so on...
Also, see NHibernate Eager loading multi-level child objects for one time eager loading
Added:
Additional info on Sql N+1:
http://nhprof.com/Learn/Alerts/SelectNPlusOne