Пределы проекций NHibernate (QueryOver.SelectList)

Я новичок в stackoverflow, и я надеюсь, что этот вопрос будет оценен по достоинству.

Проще говоря: я выбираю все из таблицы x левой внешней таблицы соединения y. В таблице x слишком много столбцов, поэтому я создаю новый объект x. Этот объект используется для проекции. Я могу проецировать каждый столбец таблицы x, который захочу. Но когда я пытаюсь спроецировать / выбрать коллекцию (коллекцию таблицы y), я получаю ту же ошибку: «Индекс находился за пределами массива».

Мой вопрос: поддерживает ли NHibernate вообще выбор / проектирование коллекции? Потому что я видел этот вопрос несколько раз, выполняя поиск в Google (и stackoverflow), но ни на один из этих вопросов не было дано ответа.

Пример кода:

public class X
{
    public virtual int ID { get; set; }
    public virtual int IDontNeedMoreInfoAboutClassXItTakesToMuchTimeToRetrieve { get; set; }
    public virtual IList<Y> YCollection { get; set; }
}

public class Y
{
    public virtual int YID { get; set; }
}

public class XRepository{
    public ISession Session {get; set;}
    public IList<X> Get()
    {

        X xAlias = null;
        Y yAlias = null;
        X resultAlias = null;
        return Session.QueryOver<X>()
            .JoinAlias(() => xAlias.YCollection, () => yAlias, JoinType.LeftOuterJoin)
            .SelectList(list => list
                .SelectGroup(() => xAlias.ID).WithAlias(() => resultAlias.ID)
                .SelectGroup(() => xAlias.YCollection).WithAlias(() => resultAlias.YCollection)) // Index was outside the bounds of the array
                .TransformUsing(Transformers.AliasToBean<X>()).List<X>();
    }
}

person PcPulsar    schedule 24.08.2012    source источник
comment
Итак, X это DTO или сопоставленный класс?   -  person Andrew Whitaker    schedule 24.08.2012
comment
Хороший вопрос: X - отображаемый класс. Я знаю, что использую сопоставленный класс в качестве результата (resultAlias), но это не имеет большого значения, если я использую dto или сопоставленный класс в качестве возвращаемого объекта. Речь идет только об игнорировании некоторых столбцов в инструкции select sql.   -  person PcPulsar    schedule 24.08.2012
comment
Я не думаю, что тебе нужно присоединиться к тебе самому. Если коллекция Y отображена правильно, то все, что вам нужно сделать, это Session.QueryOver<X>().Fetch(x => x.YCollection).Eager. nHib сгенерирует для вас левое внешнее соединение. Любое из свойств X, которое вам не нужно, можно установить на Fetch().Lazy   -  person J. Ed    schedule 24.08.2012
comment
Это может быть неплохим способом решения моей проблемы. К сожалению, в большинстве случаев мне нужно каждое свойство объекта x. Его только для 1 функции мне нужно иметь только несколько свойств объекта x. В объекте x около 30 столбцов. Большинство столбцов будут использоваться в другом месте. Теперь у меня есть одна функция, которая должна получить около 10.000 записей. Эта функция очень медленная. Тестирование на mssql занимает всего 1/4 времени, когда я использую всего несколько столбцов. Приведенный выше код является отличным примером для явного выбора необходимых мне элементов. Похоже, что только коллекции по-прежнему не работают (dto - тоже вариант, кстати).   -  person PcPulsar    schedule 27.08.2012


Ответы (1)


возвращаемые результаты должны быть сгруппированы с неповрежденным содержимым (поэтому sql отсутствует, поскольку он может агрегировать только сгруппированные элементы), но NHibernate может делать это только для m, добавленных сущностей, потому что там он знает идентичность для группировки. Сделать это вручную просто

Y yAlias = null;
var tempResults = Session.QueryOver<X>()
     .JoinAlias(x => x.YCollection, () => yAlias, JoinType.LeftOuterJoin)
     .SelectList(list => list
         .Select(() => xAlias.Id)
         .Select(() => xAlias.Name)
         ...
         .Select(() => yAlias.Id)
         ...
     .ToList<object[]>()

List<X> results = new List<X>(100); // switch to Hashset if too slow and order does not matter
foreach(var row in tempResults)
{
    Y y = new Y { Id = (long)row[4], ... };
    X x = results.FirstOrDefault(x => x.Id == (long)row[0]));
    if (x != null)
        x.YCollection.Add(y);
    else
        results.Add(new X { Id = (long)row[0], ..., YCollection = { y } };
}

return results;
person Firo    schedule 28.08.2012
comment
Если я правильно понимаю: мне нужно получить плоские результаты в tmpResults, а затем я должен воссоздать правильные объекты. Думаю, я понимаю, почему это должно быть реализовано именно так. Спасибо, я попробую это решение как можно скорее! - person PcPulsar; 29.08.2012
comment
Спасибо за решение. Самая большая разница, которую я использовал, - это использование временного (сглаженного) dto для хранения данных вместо object []. Теперь я могу предотвратить ошибки во время выполнения, чтобы повысить производительность бокса. - person PcPulsar; 30.08.2012