为啥这两个 NHibernate 查询会产生不同的结果?
Posted
技术标签:
【中文标题】为啥这两个 NHibernate 查询会产生不同的结果?【英文标题】:Why do these two NHibernate queries produce different results?为什么这两个 NHibernate 查询会产生不同的结果? 【发布时间】:2011-06-01 18:16:04 【问题描述】:这是一个 M:N 关系,集合在 NHibernate 中被映射为一个集合。
我们之前使用的条件查询“有效”,但它没有正确填充技能集合,因为只有第一个/寻找的技能被删除,即使员工有多种技能。
我将其更改为 LINQ 查询,它解决了问题,正确获取了该员工的所有技能。
Dim sId = 1 ' Just to have one for example
Dim lstEmployees = Session.CreateCriteria(Of Employee)() _
.CreateAlias("Skills", "s", NHibernate.SqlCommand.JoinType.LeftOuterJoin) _
.Add(Expression.Or(Expression.Eq("PrimarySkillId", sId),
Expression.Eq("s.Id", sId))) _
.SetResultTransformer(New DistinctRootEntityResultTransformer()) _
.List(Of Employee)()
' Returns correct employees but only their first skill in the Skills collection, even if they have more than one
Dim lstEmployees = (From e In Session.Query(Of Employee)()
Where e.PrimarySkillId =sId OrElse e.Skills.Any(Function(s) s.Id = sId)
Select e Distinct).Fetch(Function(e) e.Skills).ToList()
' Returns correct employees and their Skills collection contains all of their skills
有人了解这两个看似等效的查询有什么不同吗?
【问题讨论】:
你对比过两者生成的SQL查询吗?这应该会给你一个关于问题所在的提示。 是的,但我不确定为什么它在代码中看起来与我相同时会有所不同。第二个查询使用了一个EXISTS
语句子查询,第一个根本没有这样做。
【参考方案1】:
首先,第一个查询在检索所有行后进行了不同的分离,而第二个查询实际上执行了select distinct ...
。可能发生的情况是,它只用检索到的一项技能来为 Employee 模型补充水分
要使第一个查询实际执行select distinct ...
,您需要使用投影。
类似
Session.CreateCriteria(Of Employee)() _
.CreateAlias("Skills", "s", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.Add(Expression.Or(Expression.Eq("PrimarySkillId", sId),
Expression.Eq("s.Id", sId))) _
.SetProjection(Projections.Distinct("Id")) _
.SetFetchMode("s", FetchMode.Eager)
可能会起作用。或者,您可以尝试使用 DistinctRootEntityResultTransformer 设置获取模式
Session.CreateCriteria(Of Employee)() _
.CreateAlias("Skills", "s", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.Add(Expression.Or(Expression.Eq("PrimarySkillId", sId),
Expression.Eq("s.Id", sId))) _
.SetResultTransformer(Transformers.DistinctRootEntityResultTransformer) _
.SetFetchMode("s", FetchMode.Eager)
【讨论】:
我看看这是否有效;我曾尝试过SetFetchMode
,但我在CreateAlias
之前做过,我做过SetFetchMode("Skills", FetchMode.Eager)
。它似乎不起作用,所以也许它最后出现或使用别名“s”很重要?
谢谢 Vadim,我两种方法都试过了,都不管用。对于第一个,它似乎只选择了 Id 属性,不能将其转换为员工列表。对于第二个,它仍然是具有相同结果的相同查询。我想知道,根据 LINQ,它是一个 EXISTS 子查询。也许一个独立的标准会起作用?不过,我不知道该怎么做。
@subkamran,这将是我的下一个建议,但这些有点复杂。
LINQ 工作正常,我对此表示满意,但 FetchMany
在 NH3.1 和 VB.NET 中已损坏。我想获取一些孙子记录,但在他们修复它之前我不能,所以这就是为什么我有兴趣让它在 Criteria 中工作。以上是关于为啥这两个 NHibernate 查询会产生不同的结果?的主要内容,如果未能解决你的问题,请参考以下文章
当 CacheMode=Ignore 时,为啥 NHibernate.ISession.CreateQuery 会返回与 CreateSQLQuery 不同的东西?
Google Location API vs. Maps:为啥相同的查询会产生不同的结果?