NHibernate - QueryOver Запросы
В этой главе мы рассмотрим запросы QueryOver. Это новый синтаксис, который больше похож на LINQ, использующий синтаксис цепочки методов, как показано в следующем запросе.
var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "Laverne");
Это все еще скрытые критерии, но теперь наши запросы строго типизированы.
Как мы видели в запросе критериев, первое имя - это просто непрозрачная строка, теперь мы фактически используем x.FirstName, поэтому первое имя подвергается рефакторингу и переименованию, которое изменяется в запросе критериев стиля ссылки с использованием запроса over.
Мы по-прежнему можем делать много похожих вещей, но вы не можете использовать синтаксис понимания запроса с запросом, вы должны использовать синтаксис цепочки методов, и вы не можете смешивать и сопоставлять ссылку и критерии.
Для большого количества запросов запрос через API очень полезен и обеспечивает гораздо более легкий для понимания синтаксис объекта, чем использование критериев напрямую.
Давайте рассмотрим простой пример, в котором мы получим клиента по имени Лаверн с помощью запроса.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customers = session.QueryOver<Customer>()
.Where(x => x.FirstName == "Laverne");
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Как видите, это все еще скрытые критерии, но это просто более приятный синтаксис.
Когда приведенный выше код скомпилирован и выполнен, вы увидите следующий результат.
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 4/4/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
Press <ENTER> to exit...
Одним из недостатков является то, что, допустим, мы хотим сказать, что FirstName.StartsWith(“A”) как показано в следующей программе.
var customers = session.QueryOver<Customer>() .Where(x => x.FirstName.StartsWith("A"));
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
tx.Commit();
Теперь давайте снова запустим приложение, и вы увидите, что это не поставщик LINQ, поскольку он не знает, что это StartsWith метод есть, поэтому вы получите RunTime exception.
Исключение говорит о нераспознанном вызове метода. Здесь мы делаем очевидное, но это не обязательно работает.
Давайте попробуем что-нибудь еще, например, FirstName равно «A%», как показано в следующем коде.
var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "A%");
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
Давайте запустим это еще раз, и вы увидите, что мы не получим никаких результатов, как показано ниже.
Press <ENTER> to exit...
Чтобы понять, почему мы не получаем никаких результатов, давайте взглянем на профилировщик NHibernate.
Как видите, имя равно A%, чего нет. % Используется в SQL с оператором like. Теперь нам нужно создать ограничение для предложения WHERE, как показано в следующей программе.
var customers = session.QueryOver<Customer>()
.Where(Restrictions.On<Customer>(c => c.FirstName).IsLike("A%"));
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
Давайте снова запустим ваше приложение, и вы увидите, что все клиенты получены с именем, начинающимся с A.
Alejandrin Will (4ea3aef6-6bce-11e1-b0b4-6cf049ee52be)
Points: 24
HasGoldStatus: False
MemberSince: 10/1/2011 12:00:00 AM (Utc)
CreditRating: VeryVeryGood
AverageRating: 0
Orders:
Order Id: 4ea3aef6-6bce-11e1-b0b5-6cf049ee52be
Austyn Nolan (4ea871b6-6bce-11e1-b110-6cf049ee52be)
Points: 67
HasGoldStatus: True
MemberSince: 12/29/2007 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea871b6-6bce-11e1-b111-6cf049ee52be
Antonia Murphy (4ea871b6-6bce-11e1-b121-6cf049ee52be)
Points: 72
HasGoldStatus: True
MemberSince: 6/15/2009 12:00:00 AM (Utc)
CreditRating: Terrible
AverageRating: 0
Orders:
Order Id: 4ea871b6-6bce-11e1-b122-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b123-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b124-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b125-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b126-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b127-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b128-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b129-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b12a-6cf049ee52be
Он работает так же, как и раньше, за исключением использования этого нового QueryOverсинтаксис. Многие разработчики считают синтаксис LINQ более доступным и часто делает правильные вещи.
Если LINQ не справляется с этим, вы начнете смотреть на HQL или Criteria, чтобы увидеть, будет ли это более подходящим.
Он просто дает вам другой синтаксис, поэтому Criteria, как критерии создания, так и QueryOver, предоставляют вам еще один механизм запросов, который позволяет вам извлекать данные из базы данных с помощью NHibernate.