基本上我在这个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>();
答案 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