gpt4 book ai didi

c# - NHibernate Filtered Child Collection Lazy Loaded even with eager fetch specified

转载 作者:行者123 更新时间:2023-11-30 17:43:34 24 4
gpt4 key购买 nike

我试图找出为什么即使在急切加载集合并且生成的 SQL 正确时,也没有过滤就返回子集合。

类的流畅映射是:

public class OptionIdentifierMap : ClassMap<OptionIdentifier>
{
public OptionIdentifierMap()
: base("OptionIdentifier")
{
//Id Mapping Removed
HasMany<OptionPrice>(x => x.OptionPrices)
.KeyColumn("OptionIdentifier_id")
.Cascade.None();
}
}

public class OptionPriceMap : ClassMap<OptionPrice>
{
public OptionPriceMap()
: base("OptionPrice")
{
//Id Mapping removed
References(x => x.Option)
.Column("OptionIdentifier_id")
.Cascade.None()
.ForeignKey("FK_OptionPrice_OptionIdentifier_id_OptionIdentifier_Id")
.Not.Nullable();
References(x => x.Increment)
.Column("PricingIncrement_id")
.Cascade.None()
.ForeignKey("FK_OptionPrice_PricingIncrement_id_PricingIncrement_Id")
.Not.Nullable();
Map(x => x.Price).Not.Nullable();
}
}

和PricingIncrement映射

public class PricingIncrementMap : ClassMap<PricingIncrement>
{
public PricingIncrementMap()
: base("PricingIncrement")
{
Map(x => x.IncrementYear);
HasMany<OptionPrice>(x => x.Options)
.KeyColumn("PricingIncrement_id")
.Cascade.None().Inverse();
}
}

实体是:

public class PricingIncrement : Entity
{
public PricingIncrement()
{
Options = new List<OptionPrice>();
}

public virtual int IncrementYear { get; set; }
public virtual IList<OptionPrice> Options { get; set; }
}

public class OptionPrice : Entity
{
public OptionPrice()
{
}

public virtual OptionIdentifier Option { get; set; }
public virtual PricingIncrement Increment { get; set; }
public virtual float Price { get; set; }
}

public class OptionIdentifier : Entity
{
public OptionIdentifier()
{
OptionPrices = new List<OptionPrice>();
}
public virtual IList<OptionPrice> OptionPrices { get; set; }
}

我正在尝试查询所有具有特定 PricingIncrement 的选项价格值的 OptionIdentifier。nhibernate 根据我的标准生成的 SQL 查询是:

SELECT this_.Id                      as Id37_4_,
.......
FROM OptionIdentifier this_ inner join OptionPrice op2_ on this_.Id = op2_.OptionIdentifier_id
inner join PricingIncrement i3_ on op2_.PricingIncrement_id = i3_.Id
WHERE (this_.IsDeleted = 0)
and this_.Id in (7)
and i3_.IncrementYear = 2015

我用来构建此查询的条件是:

ICriteria pagedCriteria = this.Session.CreateCriteria<OptionIdentifier>()
.CreateAlias("OptionPrices", "op", JoinType.InnerJoin)
.CreateAlias("op.Increment", "i", JoinType.InnerJoin)
.SetFetchMode("op", FetchMode.Eager)
.SetFetchMode("i", FetchMode.Eager)
.Add(Restrictions.Eq("i.IncrementYear", 2015))
.Add(Expression.In("Id", idList.ToList<int>()))
.SetResultTransformer(CriteriaSpecification.DistinctRootEntity);

当查看 SQL Profiler 时,查询执行且结果正确,我为 OptionPrice 表中符合条件的每个 child 获得一行,在我的例子中,来自匹配 OptionIdentifier 的可用 4 行(有PricingIncrement 中有 4 行,OptionPrice 中有 4 行,每个 PricingIncrement 对应 OptionIdentifier_id 7)

但是当我尝试迭代集合以获取一些值时,出于某种原因 nhibernate 正在加载子集合,就像指定了延迟加载一样,并加载了完整的 4 个子行。阅读文档 FetchMode 应该可以解决这个问题,防止 nhibernate 延迟加载子集合。类似于 N+1 常见问题。

我检查了 SQL Profiler 以查看发生了什么,当我尝试访问它时,nhibernate 正在生成没有原始过滤器的查询来填充子集合。如果我不访问集合,则不会生成查询。

做一些测试我尝试了不同的连接类型和获取模式,到目前为止,在没有休眠加载所有元素的情况下迭代集合的唯一方法是在连接类型 LeftOuterJoin 中指定,但这意味着不同的东西。

我试图搜索类似的问题,但他们都说预加载应该有效,或者提到我应该使用过滤器。到目前为止,我还没有找到任何答案。

非常感谢任何帮助。

最佳答案

我想分享我的方法,也许不是答案......

我。避免获取一对多 (集合)

在创建任何类型的复杂查询(ICriteria、QueryOver)时,我们应该仅在开始 架构上使用(LEFT) JOIN。 IE。 多对一 (References() 流利)。从分页的角度来看,这会导致预期的行数(每个根实体始终只有一行)

为了避免集合的 1 + N 问题(但实际上即使是多对一)我们有 NHiberante 强大的功能:

19.1.5. Using batch fetching

NHibernate can make efficient use of batch fetching, that is, NHibernate can load several uninitialized proxies if one proxy is accessed (or collections. Batch fetching is an optimization of the lazy select fetching strategy)...

在这里阅读更多:

因此,在我们的例子中,我们将像这样调整映射:

public PricingIncrementMap()
: base("PricingIncrement")
{
Map(x => x.IncrementYear);
HasMany<OptionPrice>(x => x.OptionPrices)
.KeyColumn("OptionIdentifier_id")
.Cascade.None()
.Inverse() // I would use .Inverse() as well
// batch fetching
.BatchSize(100);
}

二。集合过滤

因此,我们设法避免了 1 + N 问题,并且我们也只查询星型模式。现在,我们如何加载我们集合中刚刚过滤的项目集?好吧,我们拥有原生且非常强大的 NHibernate 功能:

18.1. NHibernate filters.

NHibernate adds the ability to pre-define filter criteria and attach those filters at both a class and a collection level. A filter criteria is the ability to define a restriction clause very similiar to the existing "where" attribute available on the class and various collection elements...

在这里阅读更多相关信息:

所以在我们的例子中我们会定义过滤器

public class CollFilter : FilterDefinition
{
public CollFilter()
{
WithName("CollFilter")
.WithCondition("PricingIncrement_id = :pricingIncrementId")
.AddParameter("pricingIncrementId",NHibernate.Int32);
}
}

我们需要再次扩展我们的映射:

HasMany<OptionPrice>(x => x.OptionPrices)
.KeyColumn("OptionIdentifier_id")
.Cascade.None()
.Inverse()
// batch fetching
.BatchSize(100)
// this filter could be turned on later
.ApplyFilter<CollFilter>();

现在,在执行查询之前,我们只需启用该过滤器并提供正确的 2015 年 ID:

// the ID of the PricingIncrement with year 2015
var pricingIncrementId thes.Session
.QueryOver<PricingIncrement>()
.Where(x => x.IncrementYear == 2015)
.Take(1)
.Select(x => x.ID)
.SingleOrDefault<int?>();

this.Session
.EnableFilter("CollFilter")
.SetParameter("pricingIncrementId", pricingIncrementId);

// ... the star schema query could be executed here

三。过滤根实体的子查询

最后,我们可以使用子查询来限制我们的查询返回的根实体的数量。

15.8. Detached queries and subqueries

在这里阅读更多相关信息:

所以,我们的子查询可以是

// Subquery
var subquery = DetachedCriteria.For<OptionPrice >()
.CreateAlias("Increment", "i", JoinType.InnerJoin)
.Add(Restrictions.Eq("i.IncrementYear", 2015))
.SetProjection(Projections.Property("Option.ID"));

// root query, ready for paging, and still filtered as wanted
ICriteria pagedCriteria = this.Session.CreateCriteria<OptionIdentifier>()
.Add(Subqueries.PropertyIn("ID", subquery))
.SetResultTransformer(CriteriaSpecification.DistinctRootEntity);

总结:我们可以使用 NHibernate 附带的许多功能。他们在那里是有原因的。与它们一起,我们可以实现稳定可靠的代码,为进一步扩展(首先分页)做好准备

注意:也许我打错了一些...但总体思路应该很清楚

关于c# - NHibernate Filtered Child Collection Lazy Loaded even with eager fetch specified,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30744015/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com