2012-02-14 2 views
1

В основном я пересекла ту же проблему поставщика Linq в этом linq-to-nhibernate-produces-unnecessary-joinsДублирование и ненужными присоединяется при использовании Linq в NHibernate

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

Еще один Edit:

Я думаю, что я наконец-то узнал, что происходит. Похоже, что провайдер LINQ to NHibernate испытывает трудности с перемещением ассоциаций из целевой в исходную таблицу и генерирует отдельное соединение каждый раз, когда сталкивается с такой ассоциацией.

Поскольку вы не предоставляете свое сопоставление, я использовал отображение от linq-to-nhibernate-produces-unnecessary-joins. Эта модель имеет Документ с одним заданием и многими TranslationUnits. Каждый TranslationUnit имеет множество Перевод объектов.

При попытке найти перевод, основанный на задании, вы обходите ассоциации в обратном порядке, а поставщик LINQ создает несколько объединений: один для Translation -> TranslationUnit и один для TranslationUnit для Document.

Этот запрос будет генерировать избыточные присоединяется:

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

Если изменить порядок навигации в Document -> -> единицы трансляции перевода, вы получите запрос, который не производит какие-либо избыточное присоединяется:

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 выглядит как лучший вариант.

Предыдущая Edit:

Я подозреваю, что виновником является compset.A.B.CurrentSeason. Первая объединенная таблица (fwbcompeti1_) возвращает A .B, а следующие два (fwbcompeti2_ и fwbseason3_) используются для возврата A. B. Поставщик LINQ to NHibernate, похоже, не догадывается, что A не используется нигде и не удаляет его из сгенерированного оператора.

Попробуйте помочь оптимизатору, заменив CurrentSeason = compset.A.B.CurrentSeason с CurrentSeason = true от выберите, так как оператор where возвращает только элементы с CurrentSeason == true.

EDIT: Что я имею в виду, чтобы изменить запрос, как это:

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 с истинным

+0

Но познакомит вопрос Performence. Сначала вам нужно вернуть 2 строки данных текущего сезона, используя альтернативное решение (CurrentSeason = true from the selec), система вернет столы строк данных – ValidfroM

+0

Изменение значений, которые вы возвращаете для определенного поля в выбранной части, не будет измените количество возвращаемых строк. Что вы имеете в виду? –

+0

Спасибо, Панайотис, теперь я понял и попытался. Непосредственно он дал тот же SQL. Думаю, мне придется переключиться на QueryOver API. – ValidfroM

Смежные вопросы