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 關注
- 118 瀏覽
添加回答
舉報