2012-02-14 28 views
1

基本上我越过LINQ提供的同样的问题,在此linq-to-nhibernate-produces-unnecessary-joins重复的和不必要的NHibernate的使用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>(); 

回答

3

然而,另一个编辑:

我想我终于找到了这是怎么回事。看起来,LINQ to NHibernate提供者无法将关联从目标导航到源表,并在每次遇到这种关联时生成一个单独的连接。

由于您不提供您的映射,我使用了linq-to-nhibernate-produces-unnecessary-joins的映射。此型号有一个文档一个作业和许多TranslationUnits。每个TranslationUnit有很多翻译实体。

当您尝试根据作业查找翻译时,您正在以相反顺序遍历关联,并且LINQ提供程序会生成多个连接:一个用于翻译 - >翻译单元,另一个用于翻译单元到文档。

这个查询会产生多余的加入:

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

如果颠倒导航为了记录 - > TranslationUnit - >翻译,你会得到不产生查询的任何冗余连接:

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 = compset.A.B来帮助优化器。CurrentSeasonCurrentSeason = true from select,因为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(); 

我只是与真正的

+0

替换值compset.A.B.CurrentSeason但它会引入性能自动问题。 Image您原本只需要返回当前季节的2行数据,通过使用替代解决方案(CurrentSeason = true,从选择部分),系统将返回hundredes数据行 – ValidfroM 2012-02-14 14:47:19

+0

更改您为选择部分中的特定字段返回的值不会更改返回的行数。你什么意思? – 2012-02-14 15:23:40

+0

谢谢Panagiotis,现在我明白了你的观点并试了一试。不幸的是,它给出了相同的SQL。认为我将不得不切换到QueryOver API。 – ValidfroM 2012-02-15 09:10:27