在NHibernate中使用Linq时重复和不必要的连接

时间:2012-02-14 12:46:53

标签: nhibernate fluent-nhibernate linq-to-nhibernate

基本上我在这个linq-to-nhibernate-produces-unnecessary-joins

中遇到了与Linq提供商相同的问题
List<Competitions> dtoCompetitions;
dtoCompetitions = (from compset in session.Query<FWBCompetitionSet>()
                    where compset.HeadLine == true 
                    && compset.A.B.CurrentSeason == true
                   select (new Competitions
                           {
                                       CompetitionSetID = compset.CompetitionSetID,
                                       Name = compset.Name,
                                       Description = compset.Description,
                                       Area = compset.Area,
                                       Type = compset.Type,
                                       CurrentSeason = compset.A.B.CurrentSeason,
                                       StartDate = compset.StartDate
                            }
                    )).ToList();

这导致其生成的SQL中的重复连接

SELECT fwbcompeti0_.competitionsetid AS col_0_0_,
   fwbcompeti0_.name             AS col_1_0_,
   fwbcompeti0_.DESCRIPTION      AS col_2_0_,
   fwbcompeti0_.area             AS col_3_0_,
   fwbcompeti0_.TYPE             AS col_4_0_,
   fwbseason3_.currentseason     AS col_5_0_,
   fwbcompeti0_.startdate        AS col_6_0_
FROM   fwbcompetitionset fwbcompeti0_
       INNER JOIN A fwbcompeti1_
         ON fwbcompeti0_.competitionseasonid = fwbcompeti1_.competitionseasonid
       INNER JOIN A fwbcompeti2_
         ON fwbcompeti0_.competitionseasonid = fwbcompeti2_.competitionseasonid
       INNER JOIN B fwbseason3_
         ON fwbcompeti2_.seasonid = fwbseason3_.seasonid
WHERE  fwbcompeti0_.headline = @p0
       AND fwbseason3_.currentseason = @p1  

请注意这些连接,这些连接完全重复,也会影响我的SQL Server性能。

       INNER JOIN A fwbcompeti1_
         ON fwbcompeti0_.competitionseasonid = fwbcompeti1_.competitionseasonid
       INNER JOIN A fwbcompeti2_
         ON fwbcompeti0_.competitionseasonid = fwbcompeti2_.competitionseasonid

UPDATE1

在NHibernate 3.2中,这个LiNQ错误仍然有效,我找不到简单合理的Linq解决方案。 所以我用QueryOver + JoinAlias + TransformUsing完成了这项工作,对我来说很完美。

FWBCompetitionSet compset = null;
FWBCompetitionSeason compseason = null;
FWBSeason season = null;
IList<Competitions> dtoCompetitions;
dtoCompetitions = session.QueryOver<FWBCompetitionSet>(() => compset)
.JoinAlias(() => compset.FWBCompetitionSeason, () => compseason)
.JoinAlias(() => compseason.FWBSeason, () => season)
.Where(() => compset.HeadLine == true)  
.And(() => season.CurrentSeason == true)
.SelectList(
list => list
.Select(c => c.CompetitionSetID).WithAlias(() => compset.CompetitionSetID)
.Select(c => c.Name).WithAlias(() => compset.Name)
.Select(c => c.Description).WithAlias(() => compset.Description)
.Select(c => c.Area).WithAlias(() => compset.Area)
.Select(c => c.Type).WithAlias(() => compset.Type)
.Select(c => season.CurrentSeason).WithAlias(() => season.CurrentSeason)
.Select(c => c.StartDate).WithAlias(() => compset.StartDate)
)
.TransformUsing(Transformers.AliasToBean<Competitions>())
.List<Competitions>();

1 个答案:

答案 0 :(得分:3)

又一个编辑:

我想我终于知道发生了什么。似乎LINQ to NHibernate提供程序在从目标到源表的关联中导航很困难,并且每次遇到这样的关联时都会生成单独的连接。

由于您没有提供映射,我使用了linq-to-nhibernate-produces-unnecessary-joins的映射。此模型具有文档,其中包含一个作业和许多 TranslationUnits 。每个 TranslationUnit 都有许多翻译实体。

当您尝试查找基于作业的翻译时,您将以相反的顺序遍历关联,并且LINQ提供程序生成多个联接:一个用于翻译 - &gt; TranslationUnit和TranslationUnit to Document。

此查询将生成冗余连接:

session.Query<TmTranslation>()
          .Where(x => x.TranslationUnit.Document.Job == job)
          .OrderBy(x => x.Id)
          .ToList();

如果您将导航订单反转为Document - &gt; TranslationUnit - &gt;翻译,你得到一个不产生任何冗余连接的查询:

var items=(from doc in session.Query<Document>()
        from tu in doc.TranslationUnits
            from translation in tu.Translations
       where doc.Job ==job                        
       orderby translation.Id
       select translation).ToList();

鉴于这种怪癖,QueryOver似乎是一个更好的选择。

上一页修改:

我怀疑罪魁祸首是 compset.A.B.CurrentSeason 。第一个连接表(fwbcompeti1_)返回 A .B,而接下来的两个(fwbcompeti2_和fwbseason3_)用于返回A. B 。 LINQ to NHibernate提供程序似乎没有猜到A在其他任何地方都没有使用,并且无法将其从生成的语句中删除。

尝试用选择<中的 CurrentSeason = true 替换 CurrentSeason = compset.ABCurrentSeason 来帮助优化器一点/ em>,因为where语句只返回CurrentSeason == true的项目。

编辑:我的意思是更改这样的查询:

List<Competitions> dtoCompetitions;
dtoCompetitions = (from compset in session.Query<FWBCompetitionSet>()
                   where compset.HeadLine == true 
                   && compset.A.B.CurrentSeason == true
                   select (new Competitions
                       {
                                   CompetitionSetID = compset.CompetitionSetID,
                                   Name = compset.Name,
                                   Description = compset.Description,
                                   Area = compset.Area,
                                   Type = compset.Type,
                                   CurrentSeason = true,
                                   StartDate = compset.StartDate
                        }
                )).ToList();

我只需将值compset.A.B.CurrentSeason替换为true