Linq to NHibernate produces unnecessary JOINs

廉价感情. 提交于 2019-12-11 02:53:39

问题


I am using NHibernate 3.2.1. The following query

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

produces this SQL:

select   tmtranslation.id,
         tmtranslation.text,
         tmtranslation.fk_id_translation_unit

from     "TRANSLATION" tmtranslation
         inner join "TRANSLATION_UNIT" tmunit
           on tmtranslation.fk_id_translation_unit = tmunit.id
         inner join "TRANSLATION_UNIT" tmunit2
           on tmtranslation.fk_id_translation_unit = tmunit2.id
         inner join "DOCUMENT" tmdocument
           on tmunit2.fk_id_document = tmdocument.id
where    tmdocument.fk_id_job = 174
order by tmtranslation.id asc

My mapping:

public class TmTranslationMap : ClassMap<TmTranslation>
{
    public TmTranslationMap()
    {
        Table("\"TRANSLATION\"");
        LazyLoad();            
        Id(x => x.Id, "id").GeneratedBy.HiLo("hilo", "hilo_translation", "200");            
        Map(x => x.Text).Column("text");
        References<TmTranslationUnit>(x => x.TranslationUnit, "fk_id_translation_unit").Cascade.None();
        DynamicUpdate();
    }
}

public class TmTranslationUnitMap: ClassMap<TmTranslationUnit>
{
    public TmTranslationUnitMap()
    {
        Table("\"TRANSLATION_UNIT\"");
        LazyLoad();    
        Id(x => x.Id, "id").GeneratedBy.HiLo("hilo", "hilo_translation_unit", "200");
        HasMany(x => x.Translations).Inverse().KeyColumn("fk_id_translation_unit").Cascade.None();
        References<TmDocument>(x => x.Document, "fk_id_document").Not.Nullable().Cascade.None();
    }
}

public class TmDocumentMap : ClassMap<TmDocument>
{
    public TmDocumentMap()
    {
        Table("\"DOCUMENT\"");
        LazyLoad();          
        Id(x => x.Id, "id").GeneratedBy.HiLo("hilo", "hilo_document", "50");
        References<TmJob>(x => x.Job, "fk_id_job").Not.Nullable();
        HasMany(x => x.TranslationUnits).Inverse().KeyColumn("fk_id_document").Cascade.SaveUpdate();
    }
}

As you can see, one of the JOINs is useless and only makes the query run slower. Is there any way I can make the query not produce unnecessary JOINs using Linq?

Thank you.


回答1:


It seems that the LINQ to NHibernate provider has trouble navigating associations from the target to the source table and generates a separate join each time it encounters such an association: one for Translation -> TranslationUnit and one for TranslationUnit to Document.

The trick is help the provider navigate in the other direction: Document -> TranlationUnit -> Translation like this:

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();

The resulting SQL query is:

SELECT     translatio2_.Id as Id1_, translatio2_.Text as Text1_, translatio2_.TmTranslationUnitId as TmTransl3_1_
FROM         [Document] AS document0_ INNER JOIN
                  TmTranslationUnit AS translatio1_ ON document0_.Id = translatio1_.DocumentId INNER JOIN
                  TmTranslation AS translatio2_ ON translatio1_.Id = translatio2_.TmTranslationUnitId
WHERE     (document0_.JobId = @p0)
ORDER BY translatio2_.Id


来源:https://stackoverflow.com/questions/7291616/linq-to-nhibernate-produces-unnecessary-joins

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!