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

在NHibernate中使用Linq时重复和不必要的联接,nhibernate,fluent-nhibernate,linq-to-nhibernate,Nhibernate,Fluent Nhibernate,Linq To Nhibernate,基本上,我在这篇文章中遇到了与Linq提供者相同的问题 请注意这些连接,它们完全重复,也会影响SQL Server的性能 INNER JOIN A fwbcompeti1_ ON fwbcompeti0_.competitionseasonid = fwbcompeti1_.competitionseasonid INNER JOIN A fwbcompeti2_ ON fwbcompeti0_.competitionseasoni

基本上,我在这篇文章中遇到了与Linq提供者相同的问题

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

       INNER JOIN A fwbcompeti1_
         ON fwbcompeti0_.competitionseasonid = fwbcompeti1_.competitionseasonid
       INNER JOIN A fwbcompeti2_
         ON fwbcompeti0_.competitionseasonid = fwbcompeti2_.competitionseasonid
更新1

在NHibernate3.2中,这个LiNQ错误仍然有效,我找不到简单合理的LiNQ解决方案。 所以我用QueryOver+JoinAlias+Transforms完成这项工作,对我来说非常完美

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>();
fwbccompetitionset compset=null;
FWBCompetitionSeason compseason=null;
FWB季节=空;
IList数据竞争;
dtoCompetitions=session.QueryOver(()=>compset)
.JoinAlias(()=>compset.fwbccompetitionSeason,()=>compseason)
.JoinAlias(()=>compseason.FWBSeason,()=>season)
.Where(()=>compset.HeadLine==true)
.和(()=>season.CurrentSeason==true)
.选择列表(
列表=>列表
.选择(c=>c.CompetitionSetID)。使用别名(()=>compset.CompetitionSetID)
.Select(c=>c.Name).WithAlias(()=>compset.Name)
.Select(c=>c.Description).WithAlias(()=>compset.Description)
.使用别名(()=>compset.Area)选择(c=>c.Area)
.Select(c=>c.Type).WithAlias(()=>compset.Type)
.选择(c=>season.CurrentSeason)。使用别名(()=>season.CurrentSeason)
.Select(c=>c.StartDate).WithAlias(()=>compset.StartDate)
)
.TransformUsing(Transformers.AliasToBean())
.List();

又一次编辑:

我想我终于知道发生了什么。LINQ to NHibernate提供程序似乎在将关联从目标表导航到源表时遇到问题,并且每次遇到此类关联时都会生成单独的联接

因为您没有提供映射,所以我使用了中的映射。此模型有一个包含一个作业和多个TranslationUnits的文档。每个TranslationUnit都有许多翻译实体

当您尝试基于作业查找翻译时,您将以相反的顺序遍历关联,LINQ提供程序将生成多个联接:一个用于Translation->TranslationUnit,另一个用于TranslationUnit到文档

此查询将生成冗余联接:

session.Query<TmTranslation>()
          .Where(x => x.TranslationUnit.Document.Job == job)
          .OrderBy(x => x.Id)
          .ToList();
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();
session.Query()
.Where(x=>x.TranslationUnit.Document.Job==Job)
.OrderBy(x=>x.Id)
.ToList();
如果将导航顺序反转为Document->TranslationUnit->Translation,则会得到一个不会产生任何冗余联接的查询:

session.Query<TmTranslation>()
          .Where(x => x.TranslationUnit.Document.Job == job)
          .OrderBy(x => x.Id)
          .ToList();
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();
var items=(来自session.Query()中的文档)
来自tu,单位为doc.TranslationUnits
从翻译到翻译
其中doc.Job==Job
orderby translation.Id
选择translation).ToList();
鉴于这种怪癖,QueryOver似乎是一个更好的选择

上一次编辑:

我怀疑罪犯是compset.A.B。第一个联接表(fwbcompeti1_u)返回A.B,而下两个(fwbcompeti2_u和fwbseason3_u)用于返回A.B。LINQ to NHibernate提供程序似乎没有猜到A没有在其他任何地方使用,也没有从生成的语句中删除它

尝试用select中的CurrentSeason=true替换CurrentSeason=compset.a.B.CurrentSeason来帮助优化器,因为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();
列出数据竞争;
dtoCompetitions=(来自会话中的compset.Query()
其中compset.HeadLine==true
&&compset.A.B.CurrentSeason==真
选择(新比赛)
{
CompetitionSetID=compset.CompetitionSetID,
Name=compset.Name,
Description=compset.Description,
面积=组件面积,
类型=组件集类型,
CurrentSeason=true,
StartDate=compset.StartDate
}
)).ToList();

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

,但它会引入性能问题。图像您最初只需要返回当前季节的2行数据,通过使用替代解决方案(selec中的CurrentSeason=true),系统将返回100行数据更改您为所选部分中的特定字段返回的值将不会更改返回的行数。你什么意思?谢谢你,帕纳吉奥蒂斯,现在我明白你的意思了,试一下。毫无疑问,它给出了相同的SQL。我想我将不得不切换到QueryOverAPI。我终于找到了一种编写LINQ查询的方法,该查询不引入冗余连接:只需向后编写:P。检查编辑似乎是一个有希望的答案,稍后将尝试一下