NHibernate - Truy vấn QueryOver
Trong chương này, chúng ta sẽ đề cập đến các Truy vấn QueryOver. Đây là một cú pháp mới giống như LINQ bằng cách sử dụng cú pháp chuỗi phương thức như được hiển thị trong truy vấn sau.
var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "Laverne");
Nó vẫn còn là tiêu chí trong các trang bìa, nhưng bây giờ các truy vấn của chúng tôi được đánh máy mạnh mẽ.
Như chúng ta đã thấy trong truy vấn tiêu chí, tên đầu tiên chỉ là một chuỗi mờ, bây giờ chúng ta thực sự đang sử dụng x.FirstName, vì vậy tên đầu tiên được cấu trúc lại và đổi tên sẽ được thay đổi trong truy vấn tiêu chí kiểu liên kết bằng cách sử dụng truy vấn trên.
Chúng ta vẫn có thể làm nhiều điều tương tự, nhưng bạn không thể sử dụng cú pháp hiểu truy vấn với truy vấn hơn, bạn phải sử dụng cú pháp chuỗi phương pháp và bạn không thể kết hợp và kết hợp liên kết và tiêu chí.
Đối với nhiều truy vấn, truy vấn qua API rất hữu ích và cung cấp cú pháp đối tượng dễ hiểu hơn nhiều so với sử dụng Tiêu chí trực tiếp.
Hãy xem xét một ví dụ đơn giản, trong đó chúng ta sẽ truy xuất một khách hàng có tên là Laverne bằng cách sử dụng truy vấn trên.
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;
}
}
}
Như bạn có thể thấy rằng nó vẫn là Tiêu chí bên dưới bìa, nhưng chỉ là một cú pháp đẹp hơn.
Khi đoạn mã trên được biên dịch và thực thi, bạn sẽ thấy kết quả sau.
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...
Một trong những nhược điểm là, giả sử chúng tôi muốn nói rằng FirstName.StartsWith(“A”) như được hiển thị trong chương trình sau đây.
var customers = session.QueryOver<Customer>() .Where(x => x.FirstName.StartsWith("A"));
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
tx.Commit();
Bây giờ hãy chạy lại ứng dụng và bạn sẽ thấy rằng đây không phải là nhà cung cấp LINQ vì nó không biết cái này là gì StartsWith phương pháp là, vì vậy bạn sẽ nhận được một RunTime exception.
Ngoại lệ cho biết cuộc gọi phương thức không được công nhận. Ở đây chúng tôi đang làm điều hiển nhiên, nhưng nó không nhất thiết phải hoạt động.
Hãy thử một cái gì đó khác, như FirstName bằng “A%” như được hiển thị trong đoạn mã sau.
var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "A%");
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
Hãy chạy điều này một lần nữa và bạn sẽ thấy rằng chúng tôi sẽ không nhận lại bất kỳ kết quả nào như hình dưới đây.
Press <ENTER> to exit...
Để hiểu điều này tại sao chúng tôi không nhận được bất kỳ kết quả nào, chúng ta hãy xem xét hồ sơ NHibernate.
Như bạn có thể thấy rằng tên đầu tiên bằng A% mà không phải. A% được sử dụng trong SQL bằng cách sử dụng toán tử like. Bây giờ chúng ta cần tạo một hạn chế trong mệnh đề WHERE như trong chương trình sau.
var customers = session.QueryOver<Customer>()
.Where(Restrictions.On<Customer>(c => c.FirstName).IsLike("A%"));
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
Hãy chạy lại ứng dụng của bạn và bạn sẽ thấy rằng tất cả các khách hàng được truy xuất với tên bắt đầu bằng 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
Nó hoạt động giống như cách nó đã làm trước đây, ngoại trừ việc sử dụng QueryOvercú pháp. Nhiều nhà phát triển nhận thấy rằng cú pháp LINQ dễ tiếp cận hơn và thường làm những điều đúng đắn.
Nếu LINQ không thể xử lý nó, thì bạn sẽ bắt đầu xem xét HQL hoặc Criteria để xem liệu điều đó có phù hợp hơn không.
Nó chỉ cung cấp cho bạn một cú pháp khác, vì vậy Criteria, cả tiêu chí tạo và QueryOver đều cung cấp cho bạn một cơ chế truy vấn khác cho phép bạn lấy dữ liệu ra khỏi cơ sở dữ liệu bằng NHibernate.