2011-05-17 2 views
2

У меня есть два класса: Файл, Заявитель и я использую ActiveRecord 3.0 RC (NHibernate 3.1.0.4000).ActiveRecord (NHibernate) Eager Ошибка загрузки?

Файл

[ActiveRecord("`File`", Lazy = true)] 
public class File : TestProDb<File> { 

    [PrimaryKey("`Id`")] 
    public virtual long Id { get; private set; } 

    [Property("`Name`")] 
    public virtual string Name { get; set; } 

    [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Inverse = true, Lazy = true)] 
    public virtual IList<Applicant> Applicants { get; set; } 

    public File() { 
     this.Applicants = new List<Applicant>(); 
    } 
} 

Заявитель

[ActiveRecord("`Applicant`", Lazy = true)] 
public class Applicant : TestProDb<Applicant> { 

    [PrimaryKey("`Id`")] 
    public virtual long Id { get; private set; } 

    [Property("`Surname`")] 
    public virtual string Surname { get; set; } 

    [BelongsTo(Column = "IdFile", Lazy = FetchWhen.OnInvoke)] 
    public virtual File File { get; set; } 
} 

Теперь я хочу, чтобы выбрать файлы на основе некоторых Заявитель критериям. Результат Файлы должен содержать охотно загружен Кандидатов:

using (new SessionScope()) { 
    DetachedCriteria fileQuery = DetachedCriteria.For<File>(); 
    fileQuery.SetResultTransformer(new DistinctRootEntityResultTransformer()); 
    fileQuery.SetFetchMode("Applicants", NHibernate.FetchMode.Eager); 
    fileQuery.CreateCriteria("Applicants").Add(Expression.Like("Surname", "a", MatchMode.Anywhere)); 

    IList<File> files = File.FindAll(fileQuery); 
    foreach (File file in files) { 
     foreach (Applicant applicant in file.Applicants) { 
      Console.WriteLine(applicant.Surname); 
     } 
    } 
} 

От NHProof - первый запрос, когда я выполнить FindAll:

SELECT this_.[Id]   as Id1_0_1_, 
    this_.[Name]   as Name2_0_1_, 
    applicant1_.[Id]  as Id1_1_0_, 
    applicant1_.[Surname] as Surname2_1_0_, 
    applicant1_.IdFile as IdFile1_0_ 
FROM [File] this_ 
    inner join [Applicant] applicant1_ 
    on this_.[Id] = applicant1_.IdFile 
WHERE applicant1_.[Surname] like '%a%' /* @p0 */ 

От NHProof - второй запрос в цикле Console.WriteLine (заявитель. Фамилия):

SELECT applicants0_.IdFile as IdFile1_, 
    applicants0_.[Id]  as Id1_1_, 
    applicants0_.[Id]  as Id1_1_0_, 
    applicants0_.[Surname] as Surname2_1_0_, 
    applicants0_.IdFile as IdFile1_0_ 
FROM [Applicant] applicants0_ 
WHERE applicants0_.IdFile = 1 /* @p0 */ 

Почему я получаю дополнительную обратную пересылку в базу данных для каждого цикла Applicant (второй пример запроса)? Всего должен быть только один запрос БД из-за FetchMode.Eager. Я полностью смущен этим. Я даже попытался удалить ключевое слово virtual и установить для всех ленивых значений значение false. Все такой же. Это ошибка?

ответ

1

Вы получаете дополнительный запрос, потому что для NHibernate для активных ассоциаций нагрузки требуется внешнее соединение, но у вас есть внутреннее соединение в запросе. Чтобы это исправить, нужно указать:

JoinType.LeftOuterJoin 

I've had similar issue.

EDIT

Причина NHibernate требует левое соединение состоит в следующем, рассмотрим следующий код:

DetachedCriteria fileQuery = DetachedCriteria.For<File>(); 
fileQuery.SetFetchMode("Applicants", NHibernate.FetchMode.Eager); 

Если NHibernate сделал бы внутреннее соединение здесь, то файлы, у которых нет Заявителей, не будут присутствовать в результате запроса. То, вероятно, не то, что вы ожидаете.

Но когда вы создаете ограничение на имя Заявителя, вы определенно не хотите, чтобы файлы, у которых есть заявители, были пустыми. Это позволяет NHibernate оптимизировать запрос немного, но отключает ленивую загрузку.

+0

Sly, спасибо, он работает сейчас :) Я все еще просто не понимаю, почему он работает с использованием псевдонимов с LeftOuterJoin. Просто из-за ограничений? – Cosmo

+0

не уверен, что я прав, но вижу мои изменения :) – Sly

+0

Ваше решение отлично работает, я закончил использовать его в сочетании с Future(), потому что я должен сразу загрузить несколько дочерних коллекций. Благодаря! – Cosmo