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.
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:
The resulting SQL query is: