ActiveRecord (NHibernate) Ошибка загрузки? - PullRequest
2 голосов
/ 18 мая 2011

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

Файл

[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 */

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

1 Ответ

1 голос
/ 18 мая 2011

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

JoinType.LeftOuterJoin

У меня была похожая проблема.

РЕДАКТИРОВАТЬ

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

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

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

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

...