NHibernate 分页标准与 fetchmode eager。 (使用流动的NH)

发布于 2024-10-05 11:16:56 字数 1548 浏览 0 评论 0原文

问题:如何获取急切加载的条件以在根实体上返回分页结果,并将所有子集合设置为 fetchmode = eager。

我正在尝试获取包含 10 项的分页结果集,其中包含急切加载的子集合。问题是查询在整个选择周围选择了前 10 个。这会导致它仅返回前 10 个结果,包括所有连接的记录。如果第一个实体有 10 个子对象,那么我的结果集将返回 1 个加载了 10 个子对象的实体。我需要返回水合的实体和子集合(懒惰)。如果我关闭延迟加载并运行此查询,我会得到结果集中每个关联的 n+1 查询。

这是我的基本查询过程:

criteria = context.Session.CreateCriteria<Associate>();
criteria.SetMaxResults(10); //hardcoded for testing
criteria.SetFirstResult(1); //hardcoded for testing
criteria.SetFetchMode("Roles", NHibernate.FetchMode.Eager);
criteria.SetFetchMode("Messages", NHibernate.FetchMode.Eager);
criteria.SetFetchMode("DirectReports", NHibernate.FetchMode.Eager);
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());
return criteria.List<Associate>();


public AssociateMap()
    {
        ReadOnly();
        Id(x => x.AssociateId);
        Map(x => x.FirstName);
        Map(x => x.LastName);
        Map(x => x.ManagerId);
        Map(x => x.Department);
        Map(x => x.Email);
        Map(x => x.JobTitle);

        Map(x => x.LastFirstName).Formula("LTRIM(RTRIM(LastName)) + ', ' + LTRIM(RTRIM(FirstName))");

        HasMany(x => x.Messages).KeyColumn("AssociateId").Inverse().Cascade.All();
        HasMany(x => x.Roles).Element("RoleKey");
        HasMany(x => x.DirectReports).KeyColumn("ManagerId").Cascade.None().ForeignKeyConstraintName("FK_Associate_Manager");
        //HasMany(x => x.DirectReports).Element("ManagerId").CollectionType(typeof(Domain.Associate));


    }

Question: How to get an eager loaded criteria to return paged results on the root entity with all child collections set fetchmode = eager.

I am trying to get a 10 item paged result set with eager loaded child collections. The problem is the query does a select top 10 wrapped around the entire select. The causes it to return only the first 10 results including all joined records. If the first entity has 10 child objects then my result set will return 1 entity with 10 child objects loaded. I need the entities and child collections returned hydrated (lazy off). If I turn lazy loading off and run this query I get the n+1 query for each associate in result set.

This is my basic query process:

criteria = context.Session.CreateCriteria<Associate>();
criteria.SetMaxResults(10); //hardcoded for testing
criteria.SetFirstResult(1); //hardcoded for testing
criteria.SetFetchMode("Roles", NHibernate.FetchMode.Eager);
criteria.SetFetchMode("Messages", NHibernate.FetchMode.Eager);
criteria.SetFetchMode("DirectReports", NHibernate.FetchMode.Eager);
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());
return criteria.List<Associate>();


public AssociateMap()
    {
        ReadOnly();
        Id(x => x.AssociateId);
        Map(x => x.FirstName);
        Map(x => x.LastName);
        Map(x => x.ManagerId);
        Map(x => x.Department);
        Map(x => x.Email);
        Map(x => x.JobTitle);

        Map(x => x.LastFirstName).Formula("LTRIM(RTRIM(LastName)) + ', ' + LTRIM(RTRIM(FirstName))");

        HasMany(x => x.Messages).KeyColumn("AssociateId").Inverse().Cascade.All();
        HasMany(x => x.Roles).Element("RoleKey");
        HasMany(x => x.DirectReports).KeyColumn("ManagerId").Cascade.None().ForeignKeyConstraintName("FK_Associate_Manager");
        //HasMany(x => x.DirectReports).Element("ManagerId").CollectionType(typeof(Domain.Associate));


    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

逆流 2024-10-12 11:16:56

该解决方案最终使用子查询来设置最大结果。我使用 Subqueries.PropertyIn 添加了子查询。我将“条件”克隆为“限制器”,因为我在未显示的代码中添加了条件表达式。因此,我需要将这些条件克隆到子查询中,以便前 10 个选择将位于“IN”语句中。现在,我可以立即加载子集合并向根实体添加分页以获取 10 个实体,而不会出现笛卡尔或 n+1 的问题。我将尝试跟进更完整、更有组织的代码。

//criteria = context.Session.CreateCriteria<Associate>(); 
//changed criteria to DetachedCriteria.
criteria = DetachedCriteria.For<Associate>();

DetachedCriteria limiter = CriteriaTransformer.Clone(criteria); 
limiter.SetProjection(Projections.Id());
limiter.SetMaxResults(10);
criteria.Add(Subqueries.PropertyIn("AssociateId", limiter));

criteria.SetFetchMode("Roles", NHibernate.FetchMode.Eager); 
criteria.SetFetchMode("Messages", NHibernate.FetchMode.Eager); 
criteria.SetFetchMode("DirectReports", NHibernate.FetchMode.Eager); 
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer()); 
return criteria.List<Associate>(); 

The solution ended up using a subquery to set the max results. I added the subquery using Subqueries.PropertyIn. I am cloning the "criteria" to "limiter" because I added criterion expression in code not shown. So I need to clone these criterion into the subquery so the top 10 select will be in the "IN" statement. Now I can eager load the child collections and add pagination to the root entity to get 10 enties back without issues with cartesian or n+1. I will try to follow up with more complete and organized code.

//criteria = context.Session.CreateCriteria<Associate>(); 
//changed criteria to DetachedCriteria.
criteria = DetachedCriteria.For<Associate>();

DetachedCriteria limiter = CriteriaTransformer.Clone(criteria); 
limiter.SetProjection(Projections.Id());
limiter.SetMaxResults(10);
criteria.Add(Subqueries.PropertyIn("AssociateId", limiter));

criteria.SetFetchMode("Roles", NHibernate.FetchMode.Eager); 
criteria.SetFetchMode("Messages", NHibernate.FetchMode.Eager); 
criteria.SetFetchMode("DirectReports", NHibernate.FetchMode.Eager); 
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer()); 
return criteria.List<Associate>(); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文