NHibernate的linq fetch查询跨多个连接和子查询导致错误的sql

本文关键字:查询 错误 sql fetch linq NHibernate 连接 | 更新日期: 2023-09-27 18:04:08

我在sql server数据库中有四个表:

Part
-----
Id (PK)
LineId (FK)
other fields...
Line
-----
Id (PK)
ProcessId (FK)
other fields...
Process
-----
Id (PK)
ProcessTypeId (FK)
other fields...
ProcessType
-----
Id (PK)
other fields...

我试图使用linq查询与fetch来填充这些实体,然后将结果映射到视图模型dto。

我使用两个查询,一个是在Part上,我在它上应用一个过滤器来缩小结果:

var partids = s.Query<Part>()
               .Where(p => p.Line.Process.ProcessType.Id == processTypeId)
               .Select(p => p.Id);

然后使用这个查询来加载相关实体,并将第一个查询用作子查询:

var q = s.Query<Part>()
         .Fetch(p => p.Line)
         .ThenFetch(l => l.Process)
         .ThenFetch(pr => pr.ProcessType)
         .Where(p => partids.Contains(p.Id))
         .ToList();

虽然这个查询工作,但我注意到它需要很长时间才能加载。因此,使用分析器,我查看生成的SQL,它是:

SELECT part0_.Id AS Id0_0_,
       line1_.Id AS Id1_1_,
       process2_.Id AS Id2_2_,
       process3_.Id AS Id3_3_,
       part0_.Name AS Name0_0_,
       part0_.LineId AS Line3_0_0_,
       line1_.Name AS Name1_1_,
       line1_.ProcessId AS Proccess3_1_1_,
       process2_.Name AS Name2_2_,
       process2_.ProcessTypeId AS Proccess3_2_2_,
       process3_.Name AS Name3_3_
FROM part part0_
LEFT OUTER JOIN Line line1_ ON part0_.LineId=line1_.Id
LEFT OUTER JOIN Process process2_ ON line1_.ProcessId=process2_.Id
LEFT OUTER JOIN ProcessType process3_ ON process2_.ProcessTypeId=process3_.Id
WHERE part0_.Id IN
    ( SELECT part4_.Id
     FROM Part Part4_
     INNER JOIN Line Line5_ ON Part4_.LineId=Line5_.Id
     WHERE process2_.ProcessTypeId= 126 );

子查询连接回主查询在大多数情况下会导致运行非常慢。

我希望生成的SQL是这样的:
SELECT part0_.Id AS Id0_0_,
       line1_.Id AS Id1_1_,
       process2_.Id AS Id2_2_,
       process3_.Id AS Id3_3_,
       part0_.Name AS Name0_0_,
       part0_.LineId AS Line3_0_0_,
       line1_.Name AS Name1_1_,
       line1_.ProcessId AS Proccess3_1_1_,
       process2_.Name AS Name2_2_,
       process2_.ProcessTypeId AS Proccess3_2_2_,
       process3_.Name AS Name3_3_
FROM part part0_
LEFT OUTER JOIN Line line1_ ON part0_.LineId=line1_.Id
LEFT OUTER JOIN Process process2_ ON line1_.ProcessId=process2_.Id
LEFT OUTER JOIN ProcessType process3_ ON process2_.ProcessTypeId=process3_.Id
WHERE part0_.Id IN
    ( SELECT part4_.Id
     FROM Part part4_
     INNER JOIN Line Line5_ ON part4_.LineId=Line5_.Id
     INNER JOIN Process Process6_ ON Line5_.LineId=Process6_.Id
     WHERE Process6_.ProcessTypeId= 126 );

我使用NHibernate 4与linq提供程序为我所有的查询。我错过了一些东西在我的linq查询这里吗?

我目前使用的工作是将partids查询与ToList结合,然后使用内存中的id列表。但是,如果可能的话,我希望在这种情况下避免两次往返数据库。

目前使用QueryOverHQL api对我来说是不可行的,因为我所有的查询过滤器代码都使用linq.

请帮忙!

NHibernate的linq fetch查询跨多个连接和子查询导致错误的sql

不幸的是,我认为你目前使用的解决方案是你最好的选择。

这是NHibernate的一个bug,目前影响到版本4,我很确定它在3.3中也存在。

错误已被报告。