Подтвердить что ты не робот

Выбирать только определенные столбцы при использовании запросов Critera?

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

Например. Скажем, у меня есть таблица с 30 столбцами на ней, и это сопоставляется с объектом, использующим NHibernate, который является сопоставлением 1-для-1 с таблицей. Однако для конкретной функции системы я забочусь обо всех этих столбцах.

Теперь я знаю, что могу использовать HQL и сделать CreateQuery, который выполнит это, но для этого требуется создать конструктор для каждой комбинации полей, которые я бы хотел выборочно извлечь. Это может быть огромной болью с точки зрения обслуживания, так как я не буду ловить отсутствующие конструкторы до времени выполнения.

Мне нравится язык запросов Criteria, поскольку он создает параметризованный SQL вместо прямых SQL-запросов из HQL. Я вижу, что есть модель "Исключить" для исключения определенных столбцов, но в большинстве случаев я буду включать больше столбцов, чем исключать.

Благодаря комментарию ниже я просмотрел прогнозы, и это все еще не совсем идеальная ситуация для меня. При использовании следующего:

var list = session
    .CreateCriteria(typeof (Task))
    .SetProjection(Projections
                       .ProjectionList()
                       .Add(Projections.Property("Id")))
    .List();

Я получаю переменную list, просто являющуюся ints, я бы предпочел иметь свой полный объект Task, но со всеми полями, установленными в их значения по умолчанию. Возможно ли это? Все, что я вижу до сих пор, говорит "нет".

4b9b3361

Ответ 1

Да, вы можете сделать это с помощью запросов критериев с помощью прогнозов. Просто проецируйте только те свойства, которые хотите использовать, и только те, которые будут включены в предложение select скомпилированного запроса.

http://nhibernate.info/doc/nh/en/index.html#querycriteria-projection

Обновить для редактирования

Существует несколько способов сделать это, однако с некоторыми ограничениями. 1) Путь NHibernate.

var list = session.CreateCriteria(typeof (Task))
.SetProjection(Projections.ProjectionList()
                   .Add(Projections.Property("Name"), "Name")
                   .Add(Projections.Property("ID"), "ID")
)
.SetResultTransformer(Transformers.AliasToBean(typeof (Task)))
.List();

Просто присвойте имя свойства как псевдоним вашей проекции, а трансформатор AliasToBean сопоставляет эти прогнозы с фактическим классом. Ограничение этого метода заключается в том, что для любых свойств, которые вы на карте должны иметь сеттер в классе POCO, это может быть защищенный наборщик, но он должен иметь сеттер.

Вы также можете сделать это с помощью linq, а также немного другим способом

var list = session.CreateCriteria(typeof (Task))
.SetProjection(Projections.ProjectionList()
                   .Add(Projections.Property("Name"))
                   .Add(Projections.Property("ID"))
)
.List<IList>()
.Select(l => new Task() {Name = (string) l[0], ID = (Guid) l[1]});

Это просто использует linq для сопоставления индексированного списка, который выводится в новый экземпляр класса Task. Те же ограничения, что и выше, применяются, за исключением того, что это немного более тяжело, поскольку все сопоставленные свойства должны иметь открытый сеттер, потому что это то, что linq использует для заполнения объекта.

Надеюсь, это поможет вам.

Ответ 2

В ответ на ваше редактирование: Насколько я знаю, это невозможно.

Но, что вы можете сделать, это создать класс, который известен NHibernate, и который просто содержит интересующие вас свойства.

Например, класс TaskView, который содержит только определенные свойства класса Task.
Вам придется "импортировать" класс TaskView в файл hbm.xml, чтобы NHibernate знал об этом классе (см. Сопоставление импорта).
Затем вы можете использовать Projection для преобразования "Задачи" в экземпляр TaskView. Когда вы посмотрите на запрос, который генерирует NHibernate, вы увидите, что он будет извлекать только столбцы, необходимые для заполнения класса TaskView.

Что-то вроде того, что я написал здесь: NHibernate и подсчет коллекции

Ответ 3

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

NHibernate будет обрабатывать представление так же, как и любую таблицу, хотя, конечно, CRUD-операции будут проблемой при проблемах с целостностью данных.

Ответ 4

Вы пытались установить свой конструктор по умолчанию для установки значений по умолчанию? Поскольку это проблема со стороны приложения, вам решать. Кстати, зачем вам конструктор для каждой перестановки? Hibernate будет использовать либо конструктор всех аргументов, либо конструктор без аргументов, а затем использовать сеттеры, поэтому нет необходимости выполнять всю эту работу. На самом деле он может сделать больше, чем если бы я правильно напомнил, он даже может установить все частные поля без сеттеров, если он настроен правильно, хотя магия манипуляции с байтовым кодом.

Ответ 5

Я задал аналогичный вопрос, и NHibernate, похоже, не имеет наиболее распространенной функции, используемой приложениями с момента создания SQL. Возможность выбора только некоторых столбцов. Это действительно банально, и если бы я был в проекте, я бы отказался от любой логики, требующей, чтобы вы прыгали через обруч и вверх ногами, а вокруг просто выбирали только поля. Даже если есть ответ на это, я нахожу часы исследований слишком сложными для чего-то такого простого. Я знаю, что он доступен в провайдере Nhibernate linq, используя прогноз, но для чрезвычайно сложных запросов это невозможно, поэтому выберите только определенные поля. Либо все они, либо вы должны начать создавать DTO/Модели, которые не являются оригинальными, которые, на мой взгляд, не должны дублироваться, потому что пользователь просто хочет меньше записей. Список исключений/включений для обычных запросов на основе sql (а не linq) является обязательным. Я бы хотел, чтобы эти ORM сначала делали самые простые вещи. Просто игнорируйте заполнение модели, если поля не возвращаются в наборе результатов из базы данных. Я надеюсь, что кто-то может дать простое решение/хак/обходной путь.