1

我一直在努力解决为什么这个查询要求经理和他或她的团队只返回团队集合的第一个条目。显然,这是因为在查询结束时我有FirstOrDefault。我觉得FirstOrDefault可以应用到整个查询中,但它似乎也适用于Team集合。为什么这两个Fluent nHibernate查询产生不同的结果?

原始查询(只显示第一个成员在团队):

session.Query<IEmployee>() 
       .Where(p => p.PersonalNumber == PersonalNumber) 
       .Fetch(p => p.Team) 
       .Fetch(p => p.Manager) 
       .FirstOrDefault(); 

返回完整的团队,新的查询:

session.Query<IEmployee>() 
       .Where(p => p.PersonalNumber == PersonalNumber) 
       .Fetch(p => p.Team) 
       .Fetch(p => p.Manager) 
       .ToList().FirstOrDefault(); 

什么是制定此查询正确的方法是什么?我需要一种解决方法意味着我没有正确地做到这一点。

背景 - 映射:

这是经理基本的层次关系作为一个IEmployee和团队是IEmployee的一个IList。

References(x => x.Manager).Column("ManagerId"); 
HasMany(x => x.Team) 
       .AsList(index => index.Column("TeamIndex")) 
       .KeyColumn("ManagerId"); 
+0

您可以从生成的SQL告诉这是怎么发生的,因为问题查询生成的SQL“FETCH NEXT 1行仅对”这大概意味着,只有第一个加入的记录将被退回。我不清楚如何让FirstOrDefault与Fetch正常工作。 – kasey

回答

1

我们一直在努力与所述同样的问题。对我而言,这发生在从NH 3.1 - > 3.3升级时。问题在于,对于Linq,NHibernate 3.3生成一个SQL查询,其中有一个“Top(1)”语句,有效地杀死查询的“Fetch”部分。我通过从Linq切换到QueryOver来解决它。我相信这将工作:

session.QueryOver<IEmployee>() 
       .Where(p => p.PersonalNumber == PersonalNumber) 
       .Fetch(p => p.Team) 
       .Fetch(p => p.Manager) 
       .SingleOrDefault(); 
+0

有趣的是,这实际上是我经过一些实验后发现的(见下面的答案),而且我使用的是nHibernate 3.3。我想知道原始语法是否应该抛出某种异常,说它是无效的。 – kasey

3
session.Query<IEmployee>() 
      .Where(p => p.PersonalNumber == PersonalNumber) 
      .Fetch(p => p.Team) 
      .Fetch(p => p.Manager) 
      .FirstOrDefault(); 

在这个查询中FirstOrDefault工作的数据库上,你的预期。

session.Query<IEmployee>() 
      .Where(p => p.PersonalNumber == PersonalNumber) 
      .Fetch(p => p.Team) 
      .Fetch(p => p.Manager) 
      .ToList().FirstOrDefault(); 

在此查询中,ToList在数据库上工作。所有背后的工作都在ToList的结果上。所以FirstOrDefault从ToList的结果集中获取FirstOrDefault。要获得相同的结果,您需要为查询添加一个订单。当您执行无顺序的选择时,Sql不会授予结果集的相同顺序。 ToList结果中的顺序与第一个查询中的内部顺序不同。

+0

对不起,我不太明白。结果集的顺序(它总是只包含1个IEmployee,PersonalNumber是唯一的)将如何影响Employee.Team集合中有多少项目? – kasey

0

问题是我要求一个笛卡儿积(使用Fetch),但也使用FirstOrDefault;从生成的SQL中,我可以看到该组合不起作用,因为您只获得笛卡尔产品的第一行(SQL生成:“FETCH NEXT 1 ROWS ONLY”)。

如果我想要这样做,我需要编写不同类型的查询,否则只需使用ToList解决方法,在这种情况下,这并不会造成太大的伤害,因为我只希望从数据库得到一个结果。

实施例的解决方案:

session.QueryOver<IEmployee>() 
       .Where(p => p.PersonalNumber == PersonalNumber) 
       .Fetch(p => p.Team).Eager 
       .Fetch(p => p.Manager).Eager 
       .SingleOrDefault(); 
相关问题