为了账号安全,请及时绑定邮箱和手机立即绑定

如何阻止 NHibernate 读取子集合?

如何阻止 NHibernate 读取子集合?

C#
qq_遁去的一_1 2022-12-24 10:46:04
我的数据库中有文档列表。每个文档都有一个子元素集合。现在,我的方案是: - 读取文档(仅从文档表) - 关闭会话并让用户做一些工作。但是当我这样做时,Document 会尝试在某些地方加载子元素。我不想要它。我只想明确地阅读子元素。对于第一部分,我只需要阅读简单的文档值。那么有什么方法可以对 nHibernate 说——“嘿,永远不要读这个集合!”?
查看完整描述

3 回答

?
婷婷同学_

TA贡献1844条经验 获得超8个赞

将您收藏的延迟加载设置为LazyExtra,也许您的设置为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(), 仅发生在应用程序端。

使用Extravar commentsCount = post.Comments.Count()NHibernate 将仅发出计数查询,而不是读取所有行。

select count(*) from comments where post_id = 1

下面是一个示例配置,用于设置子集合的加载机制,如果您使用 NHibernate 的自动映射,您可以在BeforeMapSet事件上设置该设置:

//img1.sycdn.imooc.com//63a668080001417007260326.jpg

当您需要预先加载配置为Lazy或的子集合Extra时,请使用FetchMany


查看完整回答
反对 回复 2022-12-24
?
30秒到达战场

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


查看完整回答
反对 回复 2022-12-24
?
当年话下

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。


查看完整回答
反对 回复 2022-12-24
  • 3 回答
  • 0 关注
  • 87 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信