猿问

如何阻止 NHibernate 读取子集合?

我的数据库中有文档列表。每个文档都有一个子元素集合。现在,我的方案是: - 读取文档(仅从文档表) - 关闭会话并让用户做一些工作。

但是当我这样做时,Document 会尝试在某些地方加载子元素。我不想要它。我只想明确地阅读子元素。对于第一部分,我只需要阅读简单的文档值。

那么有什么方法可以对 nHibernate 说——“嘿,永远不要读这个集合!”?


qq_遁去的一_1
浏览 89回答 3
3回答

婷婷同学_

将您收藏的延迟加载设置为Lazy或Extra,也许您的设置为NoLazy(又名预加载)。最好将其设置为Extra而不是Lazy仅。因为当您只想获取子集合的.Count()or时,它会阻止 NHibernate 获取子集合的行.Any()。Extra就像懒惰的更懒惰的版本:)使用NoLazy&nbsp;/&nbsp;eager-loading:var&nbsp;post&nbsp;=&nbsp;session.Get<Post>(1);这将从数据库的帖子表中读取一行,并从数据库的评论表中读取一行,即使您没有从您的应用程序访问帖子的子集合评论。使用Lazy,var post = session.Get<Post>(1)只会加载帖子表中的一行,NHibernate 不会从数据库中读取帖子的子集合评论。至于懒惰与额外使用懒惰:var&nbsp;commentsCount&nbsp;=&nbsp;post.Comments.Count()这将从数据库中加载帖子的评论:select&nbsp;*&nbsp;from&nbsp;comments&nbsp;where&nbsp;post_id&nbsp;=&nbsp;1;而.Count(), 仅发生在应用程序端。使用Extra,var commentsCount = post.Comments.Count()NHibernate 将仅发出计数查询,而不是读取所有行。select&nbsp;count(*)&nbsp;from&nbsp;comments&nbsp;where&nbsp;post_id&nbsp;=&nbsp;1下面是一个示例配置,用于设置子集合的加载机制,如果您使用 NHibernate 的自动映射,您可以在BeforeMapSet事件上设置该设置:当您需要预先加载配置为Lazy或的子集合Extra时,请使用FetchMany

30秒到达战场

我发现是什么导致文档的周期从数据库加载,即使您不访问文档的周期属性。namespace NHibernateFetchJoinTest2{&nbsp; &nbsp; using System;&nbsp; &nbsp; using NHibernateFetchJoinTest2.DomainMapping;&nbsp; &nbsp; using NHibernateFetchJoinTest2.Domains;&nbsp; &nbsp; class MainClass&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public static void Main(string[] args)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; using (var session = Mapper.SessionFactory.OpenSession())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.WriteLine("SQL produced: ");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var d = session.Get<Document>(1);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.ReadLine();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //Console.WriteLine("Document's periods: ");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //foreach (var period in d.Periods)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //&nbsp; &nbsp; Console.WriteLine($"* {period.PeriodDescription}");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //}&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Console.ReadLine();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}产生这个:SQL produced:&nbsp;NHibernate:&nbsp;&nbsp;&nbsp; &nbsp; SELECT&nbsp; &nbsp; &nbsp; &nbsp; document0_.Id as id1_0_1_,&nbsp; &nbsp; &nbsp; &nbsp; document0_.DocumentDescription as documentdescription2_0_1_,&nbsp; &nbsp; &nbsp; &nbsp; periods1_.DocumentId as documentid3_1_3_,&nbsp; &nbsp; &nbsp; &nbsp; periods1_.Id as id1_1_3_,&nbsp; &nbsp; &nbsp; &nbsp; periods1_.Id as id1_1_0_,&nbsp; &nbsp; &nbsp; &nbsp; periods1_.PeriodDescription as perioddescription2_1_0_&nbsp;&nbsp; &nbsp; FROM&nbsp; &nbsp; &nbsp; &nbsp; Document document0_&nbsp;&nbsp; &nbsp; left outer join&nbsp; &nbsp; &nbsp; &nbsp; Period periods1_&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; on document0_.Id=periods1_.DocumentId&nbsp;&nbsp; &nbsp; WHERE&nbsp; &nbsp; &nbsp; &nbsp; document0_.Id=@p0;&nbsp; &nbsp; @p0 = 1 [Type: Int32 (0:0:0)]您的映射类似于以下内容。您的Lazy子集合加载设置为Lazy(而不是NoLazy),但其Fetch策略设置为Join。以机智:namespace NHibernateFetchJoinTest2.DomainMapping.Mappings{&nbsp; &nbsp; using NHibernate.Mapping.ByCode.Conformist;&nbsp; &nbsp; using NHibernateFetchJoinTest2.Domains;&nbsp; &nbsp; public class DocumentMapping : ClassMapping<Document>&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public DocumentMapping()&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Id(x => x.Id);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Property(x => x.DocumentDescription);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Bag(x => x.Periods, collectionMapping =>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; collectionMapping.Inverse(true);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; collectionMapping.Key(k => k.Column("DocumentId"));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; collectionMapping.Lazy(NHibernate.Mapping.ByCode.CollectionLazy.Lazy);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Remove this. This causes Document's Periods to load,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // even if child collection Periods is not accessed yet.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // This is evident in SQL log, it shows LEFT JOIN Period.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; collectionMapping.Fetch(NHibernate.Mapping.ByCode.CollectionFetchMode.Join);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, mapping => mapping.OneToMany());&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; public class PeriodMapping: ClassMapping<Period>&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; public PeriodMapping()&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Id(x => x.Id);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Property(x => x.PeriodDescription);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}如果删除此...collectionMapping.Fetch(NHibernate.Mapping.ByCode.CollectionFetchMode.Join);...子集合 Periods 未被其父项(文档)过早获取:SQL produced:&nbsp;NHibernate:&nbsp;&nbsp; &nbsp; SELECT&nbsp; &nbsp; &nbsp; &nbsp; document0_.Id as id1_0_0_,&nbsp; &nbsp; &nbsp; &nbsp; document0_.DocumentDescription as documentdescription2_0_0_&nbsp;&nbsp; &nbsp; FROM&nbsp; &nbsp; &nbsp; &nbsp; Document document0_&nbsp;&nbsp; &nbsp; WHERE&nbsp; &nbsp; &nbsp; &nbsp; document0_.Id=@p0;&nbsp; &nbsp; @p0 = 1 [Type: Int32 (0:0:0)]使用的重现步骤:https ://github.com/MichaelBuen/NHibernateFetchJoinTest2

当年话下

作为临时解决方案,我创建了一个简单的 hack:public class Document{&nbsp; &nbsp; IList<Periods> periods;&nbsp; &nbsp; public virtual IList<Period> Periods&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; get { return periods; }&nbsp; &nbsp; &nbsp; &nbsp; set { periods = value; }&nbsp; &nbsp; }&nbsp; &nbsp; public virtual void ResetPeriods()&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; periods = new List<Period>();&nbsp; &nbsp; }}这就是我获取文件的方式:db.BeginTransaction();IList<Document> list = db.Get<Document>();db.CommitTransaction();List<Document> result = new List<Document>();foreach (var item in list){&nbsp; &nbsp; item.ResetPeriods(); //todo: HACK! Preventing from lazy load of periods&nbsp; &nbsp; result.Add(item);}return result;当然这个集合被映射为惰性的。子集合 (Periods) 必须定义为返回变量,因为它会阻止 NHibernate Proxy 使用属性 getter。
随时随地看视频慕课网APP
我要回答