C# 如何阻止NHibernate阅读儿童收藏?
我的数据库中有文档列表。每个文档都有子元素的集合。现在,我的设想是: -读取文档(仅从文档表) -关闭会话,让用户做一些工作 但当我这样做时,文档会尝试在某些地方加载子元素。我不想要它。我只想明确地阅读子元素。对于第一部分,我只需要阅读简单的文档值C# 如何阻止NHibernate阅读儿童收藏?,c#,nhibernate,C#,Nhibernate,我的数据库中有文档列表。每个文档都有子元素的集合。现在,我的设想是: -读取文档(仅从文档表) -关闭会话,让用户做一些工作 但当我这样做时,文档会尝试在某些地方加载子元素。我不想要它。我只想明确地阅读子元素。对于第一部分,我只需要阅读简单的文档值 那么有没有办法对nHibernate说:“嘿,千万别读这个收藏!”将你的收藏的延迟加载设置为Lazy或Extra,也许你的设置为NoLazy(又称为渴望加载) 最好将其设置为Extra,而不是仅设置为Lazy。因为当您只想获取子集合的.Count()
那么有没有办法对nHibernate说:“嘿,千万别读这个收藏!”将你的收藏的延迟加载设置为
Lazy
或Extra
,也许你的设置为NoLazy
(又称为渴望加载)
最好将其设置为Extra
,而不是仅设置为Lazy
。因为当您只想获取子集合的.Count()
或.Any()
时,它将阻止NHibernate获取子集合的行Extra
就像是lazy的一个更懒惰的版本:)
用NoLazy/快速加载:
var post = session.Get<Post>(1);
var commentsCount = post.Comments.Count()
将从数据库中加载帖子的评论:
select * from comments where post_id = 1;
而.Count()
,只发生在应用程序端
使用,var commentscont=post.Comments.Count()
,NHibernate将只发出Count查询,而不是读取所有行
select count(*) from comments where post_id = 1
下面是一个示例配置,用于设置子集合的加载机制。如果使用NHibernate的自动映射,请在事件上设置该设置:
当您需要急切地加载配置为
惰性
或额外
的子集合时,使用作为临时解决方案我创建了一个简单的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>();
}
}
公共类文档
{
IList期;
公共虚拟IList周期
{
获取{返回周期;}
设置{periods=value;}
}
公共虚拟空重置周期()
{
句点=新列表();
}
}
这就是我获取文件的方式:
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;
db.BeginTransaction();
IList list=db.Get();
db.CommitTransaction();
列表结果=新列表();
foreach(列表中的变量项)
{
item.ResetPeriods();//todo:HACK!防止周期的延迟加载
结果.添加(项目);
}
返回结果;
当然,此集合被映射为惰性。
必须将子集合(句点)定义为back变量,因为它阻止NHibernate代理使用属性getter。我找到了导致文档句点从数据库加载的原因,即使您不访问文档的句点属性
名称空间NHibernateFetchJoinTest2
{
使用制度;
使用NHibernateFetchJoinTest2.DomainMapping;
使用NHibernateFetchJoinTest2.Domains;
类主类
{
公共静态void Main(字符串[]args)
{
使用(var session=Mapper.SessionFactory.OpenSession())
{
Console.WriteLine(“SQL生成:”);
var d=session.Get(1);
Console.ReadLine();
//Console.WriteLine(“文档的期间:”);
//foreach(d.期间中的var期间)
//{
//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
相反),但其获取策略设置为Join
。也就是说:
命名空间NHibernateFetchJoinTest2.DomainMapping.Mappings
{
使用NHibernate.Mapping.ByCode.Conformist;
使用NHibernateFetchJoinTest2.Domains;
公共类文档映射:类映射
{
公共文档映射()
{
Id(x=>x.Id);
属性(x=>x.DocumentDescription);
行李(x=>x.时段,收集映射=>
{
collectionMapping.Inverse(true);
Key(k=>k.Column(“DocumentId”);
Lazy(NHibernate.Mapping.ByCode.CollectionLazy.Lazy);
//删除此项。这将导致加载文档的句点,
//即使尚未访问子收集时段。
//这在SQL日志中很明显,它显示了左连接周期。
collectionMapping.Fetch(NHibernate.Mapping.ByCode.CollectionFetchMode.Join);
},mapping=>mapping.OneToMany());
}
}
公共类映射:类映射
{
公共周期映射()
{
Id(x=>x.Id);
属性(x=>x.PeriodDescription);
}
}
}
如果这是删除
collectionMapping.Fetch(NHibernate.Mapping.ByCode.CollectionFetchMode.Join);
…其父级(文档)不会过早获取子收集时段:
SQL生成:
NHibernate:
挑选
将0\u.Id记录为id1\u 0\u,
document0。DocumentDescription作为documentdescription2\u 0\u 0\u
从…起
文件0\u
哪里
document0.Id=@p0;
@p0=1[类型:Int32(0:0:0)]
使用的复制步骤:我已经将其设置为lazy。我根本不想得到那些记录。我甚至不想从数据库中获取计数,因为会话已经不存在了。这就是为什么我不想得到那些记录。嗯。。那很危险。它可能会从表中删除子收集周期。也许即使您将子集合的Lazy
加载策略设置为Lazy
(或Extra
),而不是NonLazy
,您也已将子集合的获取
策略设置为加入
?因此,即使未访问子收集期间,也会获取它。查看我的新答案。它不会删除它,因为它已过期