3 回答
TA贡献1844条经验 获得超8个赞
将您收藏的延迟加载设置为Lazy
或Extra
,也许您的设置为NoLazy
(又名预加载)。
最好将其设置为Extra
而不是Lazy
仅。因为当您只想获取子集合的.Count()
or时,它会阻止 NHibernate 获取子集合的行.Any()
。Extra
就像懒惰的更懒惰的版本:)
使用NoLazy / eager-loading:
var post = session.Get<Post>(1);
这将从数据库的帖子表中读取一行,并从数据库的评论表中读取一行,即使您没有从您的应用程序访问帖子的子集合评论。
使用Lazy
,var post = session.Get<Post>(1)
只会加载帖子表中的一行,NHibernate 不会从数据库中读取帖子的子集合评论。
至于懒惰与额外
使用懒惰:
var commentsCount = post.Comments.Count()
这将从数据库中加载帖子的评论:
select * from comments where post_id = 1;
而.Count()
, 仅发生在应用程序端。
使用Extra,var commentsCount = post.Comments.Count()
NHibernate 将仅发出计数查询,而不是读取所有行。
select count(*) from comments where post_id = 1
下面是一个示例配置,用于设置子集合的加载机制,如果您使用 NHibernate 的自动映射,您可以在BeforeMapSet事件上设置该设置:
当您需要预先加载配置为Lazy
或的子集合Extra
时,请使用FetchMany
TA贡献1828条经验 获得超6个赞
我发现是什么导致文档的周期从数据库加载,即使您不访问文档的周期属性。
namespace NHibernateFetchJoinTest2
{
using System;
using NHibernateFetchJoinTest2.DomainMapping;
using NHibernateFetchJoinTest2.Domains;
class MainClass
{
public static void Main(string[] args)
{
using (var session = Mapper.SessionFactory.OpenSession())
{
Console.WriteLine("SQL produced: ");
var d = session.Get<Document>(1);
Console.ReadLine();
//Console.WriteLine("Document's periods: ");
//foreach (var period in d.Periods)
//{
// Console.WriteLine($"* {period.PeriodDescription}");
//}
Console.ReadLine();
}
}
}
}
产生这个:
SQL produced:
NHibernate:
SELECT
document0_.Id as id1_0_1_,
document0_.DocumentDescription as documentdescription2_0_1_,
periods1_.DocumentId as documentid3_1_3_,
periods1_.Id as id1_1_3_,
periods1_.Id as id1_1_0_,
periods1_.PeriodDescription as perioddescription2_1_0_
FROM
Document document0_
left outer join
Period periods1_
on document0_.Id=periods1_.DocumentId
WHERE
document0_.Id=@p0;
@p0 = 1 [Type: Int32 (0:0:0)]
您的映射类似于以下内容。您的Lazy子集合加载设置为Lazy(而不是NoLazy),但其Fetch策略设置为Join。以机智:
namespace NHibernateFetchJoinTest2.DomainMapping.Mappings
{
using NHibernate.Mapping.ByCode.Conformist;
using NHibernateFetchJoinTest2.Domains;
public class DocumentMapping : ClassMapping<Document>
{
public DocumentMapping()
{
Id(x => x.Id);
Property(x => x.DocumentDescription);
Bag(x => x.Periods, collectionMapping =>
{
collectionMapping.Inverse(true);
collectionMapping.Key(k => k.Column("DocumentId"));
collectionMapping.Lazy(NHibernate.Mapping.ByCode.CollectionLazy.Lazy);
// Remove this. This causes Document's Periods to load,
// even if child collection Periods is not accessed yet.
// This is evident in SQL log, it shows LEFT JOIN Period.
collectionMapping.Fetch(NHibernate.Mapping.ByCode.CollectionFetchMode.Join);
}, mapping => mapping.OneToMany());
}
}
public class PeriodMapping: ClassMapping<Period>
{
public PeriodMapping()
{
Id(x => x.Id);
Property(x => x.PeriodDescription);
}
}
}
如果删除此...
collectionMapping.Fetch(NHibernate.Mapping.ByCode.CollectionFetchMode.Join);
...子集合 Periods 未被其父项(文档)过早获取:
SQL produced:
NHibernate:
SELECT
document0_.Id as id1_0_0_,
document0_.DocumentDescription as documentdescription2_0_0_
FROM
Document document0_
WHERE
document0_.Id=@p0;
@p0 = 1 [Type: Int32 (0:0:0)]
使用的重现步骤:https ://github.com/MichaelBuen/NHibernateFetchJoinTest2
TA贡献1890条经验 获得超9个赞
作为临时解决方案,我创建了一个简单的 hack:
public class Document
{
IList<Periods> periods;
public virtual IList<Period> Periods
{
get { return periods; }
set { periods = value; }
}
public virtual void ResetPeriods()
{
periods = new List<Period>();
}
}
这就是我获取文件的方式:
db.BeginTransaction();
IList<Document> list = db.Get<Document>();
db.CommitTransaction();
List<Document> result = new List<Document>();
foreach (var item in list)
{
item.ResetPeriods(); //todo: HACK! Preventing from lazy load of periods
result.Add(item);
}
return result;
当然这个集合被映射为惰性的。子集合 (Periods) 必须定义为返回变量,因为它会阻止 NHibernate Proxy 使用属性 getter。
- 3 回答
- 0 关注
- 87 浏览
添加回答
举报