NHibernate - Hướng dẫn nhanh
Trong chương này, chúng ta sẽ thảo luận về NHibernate là gì, tất cả các nền tảng mà nó có thể được triển khai, lợi thế của nó là gì và các khía cạnh khác liên quan đến nó.
NHibernate là gì?
NHibernate là một trình ánh xạ quan hệ đối tượng mã nguồn mở trưởng thành cho .NET framework. Nó được phát triển tích cực, có đầy đủ tính năng và được sử dụng trong hàng nghìn dự án thành công. Nó được xây dựng dựa trênADO.NET và phiên bản hiện tại là NHibernate 4.0.4.
NHibernate là một trình ánh xạ quan hệ đối tượng .NET mã nguồn mở và được phân phối dưới GNU Lesser General Public License.
Nó dựa trên Hibernate, một trình ánh xạ quan hệ đối tượng Java phổ biến và nó có một cơ sở mã hoạt động và trưởng thành.
Nó cung cấp một khuôn khổ để ánh xạ một mô hình miền hướng đối tượng đến một cơ sở dữ liệu quan hệ truyền thống.
NHibernate được bắt đầu bởi Tom Barrett và dự án này đã được thực hiện từ tháng 2 năm 2003, đây là cam kết đầu tiên của họ.
Đó là một dự án lớn và cung cấp rất nhiều chức năng.
Đây là một NuGet package có sẵn, giúp bạn dễ dàng thêm vào dự án.
Tại sao NHibernate?
Bây giờ câu hỏi là tại sao chúng ta cần object-relational mappers? Đó là bởi vì có một sự không kết nối giữa thế giới đối tượng và thế giới quan hệ.
Trong thế giới đối tượng, mọi thứ đều dựa trên objects; chúng tôi gọi các đối tượng là những thứ có dữ liệu của chúng tôi.
Thế giới quan hệ tất cả đều dựa trên tập hợp và chúng ta đang xử lý các bảng và hàng khác với thế giới đối tượng.
Trong thế giới đối tượng, chúng ta có unidirectional associations. Nếu khách hàng có một con trỏ đến một đơn đặt hàng, điều đó không nhất thiết có nghĩa là một đơn đặt hàng có một con trỏ quay lại khách hàng, nó có thể có hoặc có thể không.
Trong thế giới quan hệ, tất cả các hiệp hội đều bidirectional và nó có thể được thực hiện bằng khóa ngoại.
Tất cả các liên kết vốn có hai chiều, vì vậy khi chúng ta xử lý ánh xạ quan hệ đối tượng, chúng ta cũng cần phải xử lý sự ngắt kết nối này.
Trong thế giới đối tượng, chúng ta đang làm việc với các con trỏ là một hướng, trong khi trong thế giới quan hệ, chúng ta có các khóa ngoại vốn là hai hướng.
Thế giới vật thể có khái niệm kế thừa này, nơi một chiếc xe có thể có một số lớp con khác nhau, vì vậy ô tô là một loại phương tiện, thuyền là một loại phương tiện, và xe thể thao là một loại ô tô, những loại này các mối quan hệ thừa kế.
Thế giới quan hệ không có khái niệm thừa kế này.
Lập bản đồ
Vậy làm cách nào để lập bản đồ tất cả những disjoint relationships?Khái niệm ánh xạ này xuất phát từ trình ánh xạ quan hệ đối tượng. Chủ yếu có ba điều cần hiểu như thể hiện trong sơ đồ sau.
Trong ứng dụng của bạn, bạn sẽ cần các định nghĩa lớp, thường là mã C # và mã .NET của nó đại diện cho các lớp của chúng ta, chẳng hạn như lớp Nhân viên, lớp Khách hàng, lớp Đơn hàng, v.v.
Ở dưới cùng, bạn có thể thấy một lược đồ cơ sở dữ liệu, là Data Definition Language trong cơ sở dữ liệu quan hệ chỉ định bảng khách hàng trông như thế nào, bảng nhân viên trông như thế nào.
Ở giữa chúng, chúng ta có siêu dữ liệu ánh xạ cho người lập bản đồ quan hệ đối tượng biết cách dịch từ thế giới đối tượng trong C # sang thế giới cơ sở dữ liệu theo hàng và cột và các mối quan hệ khóa ngoài.
Siêu dữ liệu ánh xạ này có thể được biểu diễn theo nhiều cách khác nhau và chúng ta sẽ xem xét một số cách khác nhau này điển hình nhất trong ứng dụng NHibernate.
Nó được đại diện bởi HBM (Hibernate Mapping) tệp, là tệp XML.
Cơ sở dữ liệu được hỗ trợ
NHibernate hỗ trợ nhiều loại cơ sở dữ liệu khác nhau. Bất kỳ cơ sở dữ liệu quan hệ hiện có nào ngoài kia đều có thể được truy cập vào NHibernate.
Máy chủ SQL là cơ sở dữ liệu được hỗ trợ chính, đó là thứ mà hầu hết các nhà phát triển đang sử dụng trong quá trình phát triển, nó có lẽ là cơ sở dữ liệu phổ biến nhất.
Nó cũng works very well with Oracle.
Nó cũng hỗ trợ DB2, Firebird, MySQL, PostgreSQL, SQL Lite
Nó cũng có ODBC and OLEDB drivers.
Ngày nay, nhiều hệ thống được thiết kế với kiến trúc phân lớp, NHibernate cũng có nó và hoạt động hoàn toàn tốt với thiết kế đó.
Kiến trúc phân lớp
Kiến trúc phân lớp chia hệ thống thành một số nhóm, trong đó mỗi nhóm chứa mã giải quyết một vấn đề cụ thể và các nhóm này được gọi là các lớp. Hầu hết các ứng dụng cấp doanh nghiệp sử dụnghigh-level application architecture bao gồm ba lớp -
- Lớp trình bày
- Lớp kinh doanh
- Lớp Persistence
Ví dụ: lớp giao diện người dùng còn được gọi là lớp trình bày có thể chứa tất cả mã ứng dụng để xây dựng các trang web và xử lý thông tin nhập của người dùng.
Một lợi ích chính của phương pháp phân lớp là bạn thường có thể thực hiện các thay đổi đối với một lớp mà không có bất kỳ sự gián đoạn đáng kể nào đối với các lớp khác, do đó làm cho hệ thống lesser fragile and more maintainable.
Lớp trình bày
Đây là lớp trên cùng, chứa mã chịu trách nhiệm vẽ Giao diện người dùng, các trang, hộp thoại hoặc màn hình, thu thập thông tin đầu vào của người dùng và kiểm soát điều hướng.
Lớp kinh doanh
Lớp nghiệp vụ chịu trách nhiệm thực hiện bất kỳ quy tắc nghiệp vụ hoặc yêu cầu hệ thống nào mà người dùng sẽ hiểu như một phần của miền sự cố.
Nó cũng sử dụng lại mô hình được xác định bởi lớp bền vững.
Lớp bền vững
Lớp kiên trì bao gồm các lớp và thành phần chịu trách nhiệm lưu và truy xuất dữ liệu ứng dụng.
Lớp này cũng xác định ánh xạ giữa lớp mô hình và cơ sở dữ liệu. NHibernate được sử dụng chủ yếu trong lớp này.
Cơ sở dữ liệu
- Cơ sở dữ liệu tồn tại bên ngoài ứng dụng .NET.
- Đó là đại diện thực tế, liên tục của trạng thái hệ thống.
- Nếu cơ sở dữ liệu SQL được sử dụng, cơ sở dữ liệu này bao gồm lược đồ quan hệ và có thể là các thủ tục được lưu trữ.
Người trợ giúp / Lớp tiện ích
Mọi ứng dụng đều có một tập hợp các lớp trợ giúp hoặc tiện ích hỗ trợ các lớp khác: ví dụ: tiện ích giao diện người dùng, lớp nhắn tin, lớp Ngoại lệ và tiện ích ghi nhật ký.
Các phần tử này không được coi là các lớp, bởi vì chúng không tuân theo các quy tắc về sự phụ thuộc giữa các lớp trong một kiến trúc phân lớp.
Kiến trúc NHibernate
Đây là chế độ xem cấp cao của ứng dụng NHibernate và bạn cũng có thể thấy kiến trúc NHibernate đơn giản.
Mã ứng dụng sử dụng NHibernate ISession và IQuery API cho các hoạt động bền bỉ và chỉ phải quản lý các giao dịch cơ sở dữ liệu, lý tưởng là sử dụng NHibernate ITransaction API.
Trước khi chúng ta thực sự có thể bắt đầu sử dụng NHibernate, chúng ta cần hiểu nền tảng mà nó được xây dựng. NHibernate là một công nghệ bền vững dựa trên ý tưởng về ánh xạ quan hệ đối tượng hoặc ORM.
ORM là gì?
Ánh xạ quan hệ đối tượng (ORM) là một programming techniqueđể chuyển đổi dữ liệu giữa các hệ thống kiểu không tương thích trong ngôn ngữ lập trình hướng đối tượng. Nói cách khác, nó là khái niệm ánh xạ các đối tượng nghiệp vụ của một ứng dụng tới các bảng cơ sở dữ liệu quan hệ, để dữ liệu có thể dễ dàng được truy cập và cập nhật hoàn toàn thông qua mô hình đối tượng của một ứng dụng.
Như bạn đã biết rằng cơ sở dữ liệu quan hệ cung cấp một phương tiện tốt để lưu trữ dữ liệu, trong khi lập trình hướng đối tượng là một cách tiếp cận tốt để xây dựng các ứng dụng phức tạp.
NHibernate và ORM nói chung có liên quan nhiều nhất đến các ứng dụng có logic nghiệp vụ tầm thường, mô hình miền và một số loại cơ sở dữ liệu.
Với ORM, rất dễ dàng để tạo một lớp dịch có thể dễ dàng chuyển đổi các đối tượng thành dữ liệu quan hệ và quay lại một lần nữa.
Từ viết tắt ORM cũng có thể có nghĩa là mô hình hóa vai trò đối tượng và thuật ngữ này được phát minh trước khi ánh xạ đối tượng / quan hệ trở nên phù hợp.
Nó mô tả một phương pháp để phân tích thông tin, được sử dụng trong mô hình cơ sở dữ liệu.
Tại sao ORM?
ORM là một framework cho phép bạn ánh xạ thế giới của các đối tượng được tìm thấy trong ngôn ngữ hướng đối tượng thành các hàng trong bảng quan hệ được tìm thấy trong cơ sở dữ liệu quan hệ
Để hiểu khái niệm này, chúng ta hãy xem sơ đồ sau.
Trong sơ đồ trên, bạn có thể thấy rằng chúng ta có một bảng được gọi là Nhân viên ở phía bên phải chứa các cột với mỗi phần dữ liệu được liên kết với một nhân viên riêng lẻ.
Chúng tôi có một cột cho một Id xác định duy nhất từng nhân viên.
Một cột cho tên của nhân viên, một cột khác cho ngày gia nhập của họ và cuối cùng là một cột có tuổi của một nhân viên.
Nếu chúng ta muốn viết một số mã để lưu trữ một nhân viên mới trong các bảng, thì điều đó không dễ dàng như vậy.
Trong sơ đồ trên, bạn cũng có thể thấy rằng chúng ta có một đối tượng nhân viên có các trường cho Id, tên, ngày tham gia và tuổi.
Nếu không có ORM, chúng ta phải dịch đối tượng này thành một vài câu lệnh SQL khác nhau sẽ chèn dữ liệu nhân viên vào bảng nhân viên.
Vì vậy, viết mã để tạo SQL để thực hiện tình huống trên không khó lắm, nhưng nó hơi tẻ nhạt và khá dễ sai.
Sử dụng ORM như NHibernate, chúng ta có thể khai báo cách các lớp nhất định nên được ánh xạ tới các bảng quan hệ và để ORM hoặc NHibernate giải quyết công việc khó khăn là tạo SQL để chèn, cập nhật, xóa, trong dữ liệu truy vấn trong bảng nhân viên của chúng tôi.
Điều này cho phép chúng tôi giữ cho mã của mình tập trung vào việc sử dụng các đối tượng và để các đối tượng đó tự động được dịch sang các bảng quan hệ.
Vì vậy, thực sự những gì ORM làm là nó giúp chúng ta không phải ánh xạ các đối tượng vào bảng theo cách thủ công.
Để bắt đầu làm việc trên NHibernate, chúng ta sẽ cần Visual Studio và gói NHibernate.
Cài đặt Visual Studio
Microsoft cung cấp một free version của Visual Studio, cũng chứa SQL Server và nó có thể được tải xuống từ https://www.visualstudio.com Sau đây là các bước để cài đặt.
Step 1 - Sau khi tải xong, chạy trình cài đặt, hộp thoại sau sẽ hiển thị.
Step 2 - Nhấp vào nút Install và nó sẽ bắt đầu quá trình cài đặt.
Step 3 - Khi quá trình cài đặt hoàn tất thành công, bạn sẽ thấy hộp thoại sau.
Step 4 - Đóng hộp thoại này và khởi động lại máy tính của bạn nếu được yêu cầu.
Step 5- Bây giờ mở Visual studio từ Start Menu sẽ mở hộp thoại sau. Lần đầu tiên sẽ mất một khoảng thời gian để chuẩn bị.
Step 6 - Khi tất cả những điều này được thực hiện, bạn sẽ thấy cửa sổ chính của Visual Studio.
Cài đặt gói NHibernate
NHibernate là một trình ánh xạ quan hệ đối tượng mã nguồn mở trưởng thành cho .NET framework. Nó được phát triển tích cực, có đầy đủ tính năng và được sử dụng trong hàng nghìn dự án thành công. Bạn có thể cài đặt gói NHibernate bằng các phương pháp sau.
Tải trực tiếp
Tải xuống tệp zip từ tệp từ https://sourceforge.net/ chứa tất cả các mã nhị phân được yêu cầu.
Giải nén tệp zip này và bao gồm tất cả các tệp nhị phân này trong dự án của bạn.
Cài đặt bằng NuGet
Một cách khác để cài đặt NHibernate là sử dụng NuGet để cài đặt gói NHibernate, đây là cách dễ nhất để kết hợp NHibernate vào một dự án.
Nó sẽ tải xuống tất cả các phụ thuộc NHibernate và tạo các tham chiếu đến tất cả các hợp ngữ được yêu cầu.
Để cài đặt NHibernate, hãy chạy lệnh sau trong Bảng điều khiển Trình quản lý Gói.
install-package NHibernate
Bây giờ bạn đã sẵn sàng để bắt đầu ứng dụng của mình.
Trong chương này, chúng ta sẽ xem xét cách bắt đầu một ví dụ đơn giản bằng NHibernate. Chúng tôi sẽ xây dựng mộtsimple console application. Để tạo ứng dụng bảng điều khiển, chúng tôi sẽ sử dụng Visual Studio 2015, có chứa tất cả các tính năng bạn cần để tạo, kiểm tra ứng dụng của bạn bằng gói NHibernate.
Sau đây là các bước để tạo một dự án bằng cách sử dụng các mẫu dự án có sẵn trong Visual Studio.
Step 1 - Mở Visual studio và nhấp vào tùy chọn menu File → New → Project.
Step 2 - Một hộp thoại Dự án mới mở ra.
Step 3 - Từ khung bên trái, chọn Mẫu → Visual C # → Windows.
Step 4 - Trong ngăn giữa, chọn Ứng dụng Console.
Step 5 - Nhập tên dự án, 'NHibernateDemoApp', vào trường Tên và nhấp Ok để tiếp tục.
Step 6 - Sau khi dự án được tạo bởi Visual Studio, bạn sẽ thấy một số tệp được hiển thị trong cửa sổ Solution Explorer.
Như bạn biết rằng chúng tôi đã tạo một dự án ứng dụng bảng điều khiển đơn giản, bây giờ chúng tôi cần đưa gói NHibernate vào dự án bảng điều khiển của mình.
Vào menu Tools và chọn NuGet Package Manager → Package Manager Console, nó sẽ mở ra cửa sổ Package Manager Console.
Chỉ định lệnh hiển thị ở trên Package Manager Consolevà nhấn enter, nó sẽ tải xuống tất cả các phụ thuộc NHibernate và tạo các tham chiếu đến tất cả các hợp ngữ được yêu cầu. Sau khi cài đặt xong, bạn sẽ thấy thông báo như trong hình sau.
Bây giờ chúng tôi đã thêm NHibernate, bây giờ chúng tôi có thể bắt đầu triển khai. Vì vậy, chúng tôi sẽ bắt đầu bằng cách lập bản đồ rất đơn giảntable gọi là Student, chỉ có một khóa chính số nguyên được gọi là ID và một cột FirstName và LastName.
Chúng ta cần một lớp đại diện cho sinh viên này, vì vậy hãy tạo một lớp mới có tên là Sinh viên bằng cách nhấp chuột phải vào dự án trong trình khám phá giải pháp và sau đó chọn Thêm → Lớp sẽ mở hộp thoại Thêm Mục mới.
Đi vào Student.cstrong trường tên, nhấp vào nút Thêm. Trong lớp Sinh viên này, chúng ta cần có khóa chính số nguyên được gọi là ID và chúng ta cần tạo chuỗi này,FirstName và LastName các trường như được hiển thị trong phần triển khai hoàn chỉnh sau của lớp Sinh viên.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual int ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstMidName { get; set; }
}
}
Khi xử lý các mô hình trong ứng dụng NHibernate, việc biến tất cả các trường của bạn thành ảo là điều dễ dàng nhất. Vì vậy, đây là mô hình NHibernate đơn giản của chúng tôi mà chúng tôi sẽ sử dụng và sẽ ánh xạ mô hình này đến cơ sở dữ liệu phía sau.
Bây giờ chúng ta hãy chuyển đến phương thức Main trong lớp Program và tạo một đối tượng cấu hình NHibernate mới.
Điều đầu tiên chúng tôi cần cung cấp là connection string. Đây là một chuỗi kết nối dành riêng cho cơ sở dữ liệu và cách dễ nhất để tìm chuỗi kết nối là nhấp chuột phải vào cơ sở dữ liệu trongSQL Server Object Explorer và chọn Thuộc tính.
Nó sẽ mở Cửa sổ Thuộc tính, bây giờ hãy cuộn xuống và bạn sẽ thấy trường Chuỗi kết nối trong cửa sổ Thuộc tính.
Sao chép chuỗi Kết nối và chỉ định trong mã của bạn. Sau đây là việc thực hiện phương thức Main, trong đó chúng ta cần cấu hình cho NHibernate.
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
//perform database logic
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Sau chuỗi kết nối, chúng ta cần cung cấp một trình điều khiển, đó là SQLClientDriver và sau đó, chúng tôi cũng cần cung cấp cho nó một phương ngữ, phiên bản của SQL Server và chúng tôi sẽ sử dụng MS SQL 2008.
NHibernate hiện biết cách kết nối với cơ sở dữ liệu. Điều khác chúng ta cần làm là cung cấp cho nó một danh sách các mô hình mà chúng ta sẽ lập bản đồ.
Chúng ta có thể làm điều này bằng cách thêm một assembly, do đó, bằng cách chỉ định Assembly.GetExecutingAssemblyvà đây là nơi chương trình sẽ tìm các tệp ánh xạ. Các tệp ánh xạ cho NHibernate biết cách đi từ các lớp C # vào các bảng cơ sở dữ liệu.
SessionFactory biên dịch tất cả siêu dữ liệu cần thiết để khởi tạo NHibernate. SessionFactory có thể được sử dụng để xây dựng các phiên, gần giống với các kết nối cơ sở dữ liệu. Vì vậy, cách thích hợp là sử dụng nó trong khối using. tôi có thể nóivar session bằng sessionFactory.OpenSession và tôi sẽ muốn thực hiện điều này bên trong giao dịch của nó.
Khi phiên được mở, chúng ta có thể yêu cầu phiên bắt đầu một giao dịch mới và sau đó chúng ta có thể thực hiện một số logic tại đây. Vì vậy, thực hiện một số logic cơ sở dữ liệu và cuối cùng cam kết giao dịch đó.
Trong chương này, chúng tôi sẽ đề cập đến một số basic mappingvà bạn biết rằng từ chương trước chúng ta có bảng cơ sở dữ liệu cũng như định nghĩa lớp C #. Bây giờ chúng ta cần một ánh xạ giải thích cách dịch từ C # sang cơ sở dữ liệu và quay lại một lần nữa.
Vì vậy, hãy tiếp tục và thêm một tệp XML mới bằng cách nhấp chuột phải vào dự án trong trình khám phá giải pháp và chọn Thêm → Mục mới ...
Đi vào Student.hbm.xmltrong trường tên. Chúng tôi cần chỉ định một hội đồng mặc định sẽ làNHibernateDemoAppvà cũng chỉ định một không gian tên mặc định. Điều này chỉ rút ngắn rất nhiều định nghĩa kiểu khác mà chúng ta sẽ thực hiện trong tệp này.
Sau đây là cách triển khai trong tệp XML:
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstMidName"/>
</class>
</hibernate-mapping>
Điều tiếp theo chúng ta cần xác định một lớp; lớp học này sẽ là của chúng tôiStudent class. Tiếp theo, chúng ta cần cho NHibernate biết tên của id, đó là ID và tôi cũng phải cho NHibernate biết cách tạo ID, vì vậy trình tạo của chúng tôi sẽ là kiểu gốc.
Trình tạo kiểu gốc có nghĩa là trong cơ sở dữ liệu như SQL Server, nó sẽ sử dụng cột nhận dạng, kiểu nhận dạng.
Điều tiếp theo chúng ta phải làm là cung cấp tên của các thuộc tính. Vì vậy, hãy thêm hai thuộc tính nữa cho FirstName và LastName.
Bây giờ, chúng tôi đang đọc các tệp ánh xạ này từ assembly. Vì vậy, cách ưu tiên để làm điều này là có nhữngHBM filesnướng vào lắp ráp của bạn. Chúng tôi có thể làm điều này bằng cách đơn giản thiết lập một thuộc tính
Bây giờ nhấp chuột phải vào dự án trong trình khám phá giải pháp và chọn Thuộc tính, bạn sẽ thấy Build Action field trong đó Nội dung được chọn theo mặc định.
Chọn tài nguyên được nhúng từ danh sách thả xuống.
Vì vậy, điều này thực sự nhúng tệp XML đó vào bên trong NHibernateDemoApp hội,, tổ hợp.
Trong chương này, chúng tôi sẽ đề cập đến những điều cơ bản CRUD operations. Bây giờ hệ thống của chúng tôi đã sẵn sàng để bắt đầu, vì chúng tôi đã triển khai thành công lớp Sinh viên miền của mình, chúng tôi cũng đã xác định các tệp ánh xạ và định cấu hình NHibernate. Bây giờ chúng ta có thể sử dụng một số truy vấn để thực hiện các hoạt động CRUD.
Tạo dữ liệu
Như bạn có thể thấy rằng chúng tôi không có dữ liệu nào trong bảng Sinh viên của chúng tôi trong NHibernateDemoDB cơ sở dữ liệu.
Vì vậy, để thêm một số dữ liệu, chúng ta cần thực hiện Add/Create hoạt động như hình dưới đây.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var student1 = new Student {
ID = 1,
FirstMidName = "Allan",
LastName = "Bommer"
};
var student2 = new Student {
ID = 2,
FirstMidName = "Jerry",
LastName = "Lewis"
};
session.Save(student1);
session.Save(student2);
tx.Commit();
}
Console.ReadLine();
}
Như bạn có thể thấy rằng chúng tôi đã tạo hai sinh viên và sau đó gọi phương thức Save () của OpenSession và sau đó gọi Cam kết () của BeginTransaction. Đây là cách triển khai hoàn chỉnh trongProgram.cs tập tin
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var student1 = new Student {
ID = 1,
FirstMidName = "Allan",
LastName = "Bommer"
};
var student2 = new Student {
ID = 2,
FirstMidName = "Jerry",
LastName = "Lewis"
};
session.Save(student1);
session.Save(student2);
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Bây giờ, hãy chạy ứng dụng này và sau đó đi tới SQL Server Object Explorer và làm mới cơ sở dữ liệu của bạn. Bạn sẽ thấy rằng hai sinh viên trên hiện đã được thêm vào bảng Sinh viên trong cơ sở dữ liệu NHibernateDemoDB.
Đọc dữ liệu từ bảng sinh viên
Bạn có thể thấy rằng bây giờ chúng tôi có hai bản ghi trong bảng học sinh của chúng tôi. Để đọc các bản ghi này từ bảng, chúng ta cần gọiCreateCriteria() của OpenSession như được hiển thị trong đoạn mã sau.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}",
student.ID,student.FirstMidName, student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
Vì vậy, nếu bạn muốn danh sách bản ghi thì chúng ta có thể chỉ cần nói danh sách loại Sinh viên.
Bây giờ sử dụng foreach thông qua tất cả các sinh viên và nói in ID, FirstMidName và LastNametrên bảng điều khiển. Bây giờ, hãy chạy lại ứng dụng này và bạn sẽ thấy kết quả sau trên cửa sổ bảng điều khiển.
1 Allan Bommer
2 Jerry Lewis
Bạn cũng có thể truy xuất bất kỳ bản ghi nào bằng cách chỉ định ID trong Get() phương pháp của OpenSession bằng cách sử dụng mã sau.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID,
student.FirstMidName, student.LastName);
}
var stdnt = session.Get<Student>(1);
Console.WriteLine("Retrieved by ID");
Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID,
stdnt.FirstMidName, stdnt.LastName);
tx.Commit();
}
Console.ReadLine();
}
Bây giờ khi bạn chạy ứng dụng của mình, bạn sẽ thấy kết quả sau.
1 Allan Bommer
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Cập nhật bản ghi
Để cập nhật bản ghi trong bảng, trước tiên chúng ta cần tìm nạp bản ghi cụ thể đó và sau đó cập nhật bản ghi đó bằng cách gọi Update() phương thức của OpenSession như được hiển thị trong đoạn mã sau.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID,
student.FirstMidName, student.LastName);
}
var stdnt = session.Get<Student>(1);
Console.WriteLine("Retrieved by ID");
Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, stdnt.FirstMidName, stdnt.LastName);
Console.WriteLine("Update the last name of ID = {0}", stdnt.ID);
stdnt.LastName = "Donald";
session.Update(stdnt);
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID,
student.FirstMidName, student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
Bây giờ khi bạn chạy ứng dụng của mình, bạn sẽ thấy kết quả sau.
1 Allan Bommer
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Update the last name of ID = 1
Fetch the complete list again
1 Allan Donald
2 Jerry Lewis
Như bạn có thể thấy, LastName của ID bằng 1 được cập nhật từ Bommer thành Donald.
Xóa hồ sơ
Để xóa bất kỳ bản ghi nào khỏi bảng, trước tiên chúng ta cần tìm nạp bản ghi cụ thể đó và sau đó xóa bản ghi đó bằng cách gọi Delete() phương thức của OpenSession như được hiển thị trong đoạn mã sau.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID,
student.FirstMidName, student.LastName);
}
var stdnt = session.Get<Student>(1);
Console.WriteLine("Retrieved by ID");
Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, stdnt.FirstMidName, stdnt.LastName);
Console.WriteLine("Delete the record which has ID = {0}", stdnt.ID);
session.Delete(stdnt);
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
Bây giờ khi bạn chạy ứng dụng của mình, bạn sẽ thấy kết quả sau.
1 Allan Donald
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Delete the record which has ID = 1
Fetch the complete list again
2 Jerry Lewis
Như bạn có thể thấy rằng bản ghi có ID bằng 1 không còn có sẵn trong cơ sở dữ liệu. Bạn cũng có thể xem cơ sở dữ liệu trong SQL Server Object Explorer.
Trong chương này, chúng ta sẽ hiểu cách tất cả các bản ghi từ cơ sở dữ liệu retrieved, updated, created, and deleted và chính xác những truy vấn này được thực hiện như thế nào?
Để hiểu tất cả những điều này, chúng ta có thể chỉ cần thêm một tùy chọn vào cấu hình của mình, tùy chọn này ghi lại SQL trong bảng điều khiển. Đây là câu lệnh đơn giản sẽ ghi lại truy vấn SQL -
x.LogSqlInConsole = true;
Bây giờ, chúng tôi có hai bản ghi trong bảng sinh viên của chúng tôi trong cơ sở dữ liệu NHibernateDemoDB. Hãy lấy tất cả các bản ghi từ cơ sở dữ liệu như được hiển thị trong đoạn mã sau.
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
Console.WriteLine("\nFetch the complete list again\n");
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Vì vậy, hãy tiếp tục và chạy lại ứng dụng này, và bạn sẽ thấy kết quả sau:
NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,
this_.FirstMidName as FirstMid3_0_0_ FROM Student this_
Fetch the complete list again
3 Allan Bommer
4 Jerry Lewis
Như bạn có thể thấy, select clauseđược gửi đến cơ sở dữ liệu, nó thực sự giống như mệnh đề sẽ truy xuất ID, FirstMidName và LastName. Vì vậy, tất cả điều này đang được gửi đến cơ sở dữ liệu và xử lý ở đó thay vì có nhiều bản ghi được đưa trở lại máy chủ của bạn và xử lý ở phía máy chủ.
Hồ sơ NHibernate
Một cách khác để xem các kết quả này là sử dụng NHibernate Profiler. NHibernate Profiler là một công cụ thương mại, nhưng nó rất hữu ích để làm việc với các ứng dụng NHibernate. Bạn có thể dễ dàng cài đặt NHibernate Profiler vào ứng dụng của mình từ NuGet.
Hãy đi tới bảng điều khiển NuGet Manager từ menu Tools bằng cách chọn NuGet Package Manager → Package Manager Console. Nó sẽ mở ra cửa sổ Bảng điều khiển Trình quản lý Gói. Nhập lệnh sau và nhấn enter.
PM> install-package NHibernateProfiler
Nó sẽ cài đặt tất cả các mã nhị phân cần thiết cho NHibernate Profiler, khi nó được cài đặt thành công, bạn sẽ thấy thông báo sau.
Bạn cũng sẽ thấy rằng NHibernate Profiler được khởi chạy khi nó được cài đặt. Nó sẽ yêu cầu giấy phép để sử dụng, nhưng với mục đích demo, chúng tôi có thể sử dụng phiên bản dùng thử 30 ngày của NHibernate Profiler.
Giờ đây, NHibernate Profiler được tối ưu hóa để hoạt động với các ứng dụng web và bạn sẽ thấy rằng nó đã thêm App_Start foldertrong trình khám phá giải pháp. Để giữ cho tất cả những điều này đơn giản, hãy xóa thư mục App_Start và bạn cũng sẽ thấy rằng một câu lệnh được thêm vào đầu phương thức Main trong lớp Chương trình.
App_Start.NHibernateProfilerBootstrapper.PreStart();
Cũng xóa câu lệnh này và chỉ thêm một cuộc gọi đơn giản NHibernateProfiler.Initialize như thể hiện trong đoạn mã sau.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()){
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Bây giờ khi bạn chạy ứng dụng, nó sẽ gửi dữ liệu đến ứng dụng NHibernate Profiler.
Bạn có thể thấy ở đây, chúng tôi có một màn hình đẹp cho thấy rằng chúng tôi đã bắt đầu giao dịch, những gì SQL đang làm với cơ sở dữ liệu ở một định dạng đẹp.
Vì vậy, điều này rất hữu ích để xác định chính xác những gì đang xảy ra bên trong ứng dụng NHibernate của bạn. Nó trở nên cực kỳ hữu ích khi ứng dụng đạt đến một mức độ phức tạp nhất định, nơi bạn cần một cái gì đó giống như SQL Profiler, nhưng với kiến thức về NHibernate.
Trong chương này, chúng tôi sẽ thêm IntelliSense tới các tệp ánh xạ NHibernate của chúng tôi (*.hbm.xml files). Như bạn đã quan sát trong khi ánh xạ miền Lớp sinh viên mà hiện tại chúng tôi không có sẵn IntelliSense. Nó rất hữu ích để cóXML schemascó sẵn. Vì vậy, trong chương này, bạn sẽ hiểu cách thêm IntelliSense trong Visual Studio cho các tệp XML NHibernate này.
Mở tệp ánh xạ và bạn sẽ thấy tùy chọn menu XML xuất hiện trong menu chính.
Chọn tùy chọn menu XML → Schemas… và nó sẽ hiển thị hộp thoại XML Schemas.
Chọn nút Thêm… ở trên cùng bên phải của hộp thoại để mở hộp thoại tệp. Bây giờ đi đếnpackages folder, nằm trong thư mục Giải pháp của dự án của bạn và bạn sẽ thấy các gói khác nhau có trong dự án của mình.
Bây giờ, nhấp đúp vào NHibernate.4.*** folder và bạn sẽ thấy hai tệp lược đồ (* .xsd) hoặc tệp định nghĩa lược đồ XML xác định cấu hình và ánh xạ NHibernate.
Chọn hai tệp lược đồ này và nhấp vào nút Mở.
Bạn có thể thấy rằng các lược đồ NHibernate được thêm vào hộp thoại Lược đồ XML. Nhấp vào nút OK. Bây giờ, hãy bắt đầu một thẻ thuộc tính mới và bạn sẽ thấy rằng chúng tôi đã có đầy đủ IntelliSense ở đây.
IntelliSense hiện đã có sẵn cho bạn giúp tiết kiệm rất nhiều thời gian trong quá trình ánh xạ quan hệ đối tượng.
Trong chương này, chúng ta sẽ đề cập đến các kiểu dữ liệu ánh xạ. Ánh xạ các thực thể là đơn giản, các lớp thực thể luôn được ánh xạ tới các bảng cơ sở dữ liệu bằng cách sử dụng<class>, <subclass>, and <joined-subclass>các yếu tố ánh xạ. Các loại giá trị cần một thứ gì đó nhiều hơn, đó là nơi các loại ánh xạ được yêu cầu.
NHibernate có thể ánh xạ nhiều loại dữ liệu khác nhau. Đây là danh sách các kiểu dữ liệu phổ biến nhất được hỗ trợ.
Loại ánh xạ | Loại .NET | System.Data.DbType |
---|---|---|
Int16 | Hệ thống.Int16 | DbType.Int16 |
Int32 | Hệ thống.Int32 | DbType.Int32 |
Int64 | Hệ thống.Int64 | DbType.Int64 |
Độc thân | System.Single | DbType.Single |
Gấp đôi | Hệ thống. Đôi | DbType.Double |
Thập phân | System.Decimal | DbType.Decimal |
Chuỗi | System.String | DbType.String |
AnsiString | System.String | DbType.AnsiString |
Byte | System.Byte | DbType.Byte |
Char | System.Char | DbType.StringFixedLength — một ký tự |
AnsiChar | System.Char | DbType.AnsiStringFixedLength — một ký tự |
Boolean | System.Boolean | DbType.Boolean |
Hướng dẫn | System.Guid | DbType.Guid |
Kiên trì | System.Enum (một bảng liệt kê) | DbType cho giá trị cơ bản |
Đúng sai | System.Boolean | DbType.AnsiStringFixedLength — 'T' hoặc 'F' |
Có không | System.Boolean | DbType.AnsiStringFixedLength — 'Y' hoặc 'N' |
Ngày giờ | Ngày giờ | DbType.DateTime — bỏ qua mili giây |
Bọ ve | System.DateTime | DbType.Int64 |
TimeSpan | System.TimeSpan | DbType.Int64 |
Dấu thời gian | System.DateTime | DbType.DateTime — cụ thể như cơ sở dữ liệu hỗ trợ |
Nhị phân | System.Byte [] | DbType.Binary |
BinaryBlob | System.Byte [] | DbType.Binary |
StringClob | System.String | DbType.String |
Serializable | Any System.Object được đánh dấu bằng SerializableAttribute | DbType.Binary |
CultureInfo | System.Globalization.CultureInfo | DbType.String — năm ký tự cho văn hóa |
Kiểu | Loại hệ thống | DbType.String giữ tên hội đủ điều kiện |
Bảng trên giải thích chi tiết các điểm được đề cập bên dưới.
Mọi thứ, từ các kiểu số đơn giản đến chuỗi, có thể được ánh xạ theo nhiều cách khác nhau bằng cách sử dụng varchars, chars vv cũng như các đốm màu chuỗi và tất cả các loại khác nhau mà cơ sở dữ liệu hỗ trợ.
Nó cũng có thể lập bản đồ Booleans, cho cả các trường sử dụng số không và số một, các trường ký tự chứa true, false hoặc T và F.
Có nhiều cách xác định cách ánh xạ tới back end, các giá trị boolean trong cơ sở dữ liệu.
Chúng tôi có thể xử lý ánh xạ của DateTime, cả bao gồm và không bao gồm lệch múi giờ, thời gian tiết kiệm ánh sáng ban ngày, v.v.
Chúng tôi cũng có thể lập bản đồ enumerations; chúng ta có thể ánh xạ chúng thành chuỗi hoặc với các giá trị số cơ bản của chúng.
Hãy xem xét một ví dụ đơn giản trong đó chúng ta có các tên thuộc tính giống nhau cả trong cơ sở dữ liệu cũng như trong lớp Sinh viên.
Bây giờ chúng ta hãy thay đổi FirstMidName thành FirstName trong lớp học sinh, nơi chúng ta sẽ không thay đổi cột FirstMidName, nhưng chúng ta sẽ xem cách thông báo cho NHibernate biết để thực hiện chuyển đổi này. Sau đây là cập nhật lớp học sinh.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual int ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
}
}
Đây là việc triển khai tệp ánh xạ NHibernate.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemoApp"
namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
</class>
</hibernate-mapping>
Trong ví dụ này, giả sử rằng trường FirstName là một chuỗi .NET và cột FirstMidName là SQL nvarchar. Bây giờ để cho NHibernate biết cách thực hiện chuyển đổi này, hãy đặt tên bằngFirstName và cột bằng FirstMidName và chỉ định kiểu ánh xạ bằng Chuỗi, thích hợp cho chuyển đổi cụ thể này.
Sau đây là một Program.cs triển khai tệp.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstName,
student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Bây giờ khi bạn chạy ứng dụng của mình, bạn sẽ thấy kết quả sau.
NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,
this_.FirstMidName as FirstMid3_0_0_ FROM Student this_
Fetch the complete list again
3 Allan Bommer
4 Jerry Lewis
Như bạn có thể thấy rằng nó đã ánh xạ tên thuộc tính khác với tên cột trong cơ sở dữ liệu.
Hãy xem một ví dụ khác, trong đó chúng ta sẽ thêm một thuộc tính khác trong lớp Sinh viên của enumkiểu. Đây là phần triển khai lớp Sinh viên.
using System;
using System.Collections.Generic;
using System.Linq; using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual int ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual StudentAcademicStanding AcademicStanding { get; set; }
}
public enum StudentAcademicStanding {
Excellent,
Good,
Fair,
Poor,
Terrible
}
}
Như bạn có thể thấy rằng bảng liệt kê có nhiều giá trị khác nhau mà nó có thể có, chẳng hạn như Xuất sắc, Tốt, Khá, Kém và Kém.
Chuyển đến tệp ánh xạ, bạn có thể thấy rằng từng thuộc tính này được liệt kê trong tệp ánh xạ bao gồm cả phần mới được thêm vào AcademicStanding bất động sản.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
<property name = "AcademicStanding"/>
</class>
</hibernate-mapping>
Bây giờ chúng ta cũng cần thay đổi cơ sở dữ liệu, vì vậy hãy chuyển đến SQL Server Object Explorer và nhấp chuột phải vào cơ sở dữ liệu và chọn tùy chọn New Query….
Nó sẽ mở trình soạn thảo truy vấn và sau đó chỉ định truy vấn bên dưới.
DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[LastName] NVARCHAR (MAX) NULL,
[FirstMidName] NVARCHAR (MAX) NULL,
[AcademicStanding] NCHAR(10) NULL,
CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC)
);
Truy vấn này trước tiên sẽ xóa bảng sinh viên hiện có và sau đó tạo một bảng mới.
Clcik vào biểu tượng Execute như hình trên. Sau khi truy vấn được thực thi thành công thì bạn sẽ thấy một thông báo.
Mở rộng cơ sở dữ liệu và bảng thả xuống, sau đó bấm chuột phải vào bảng Sinh viên và chọn Xem thiết kế.
Bây giờ, bạn sẽ thấy bảng mới được tạo, bảng này cũng có thuộc tính mới là AcademicStanding.
Hãy thêm hai bản ghi như được hiển thị trong phần sau Program.cs tập tin.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var student1 = new Student {
ID = 1,
FirstName = "Allan",
LastName = "Bommer",
AcademicStanding = StudentAcademicStanding.Excellent
};
var student2 = new Student {
ID = 2,
FirstName = "Jerry",
LastName = "Lewis",
AcademicStanding = StudentAcademicStanding.Good
};
session.Save(student1);
session.Save(student2);
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
student.FirstName, student.LastName, student.AcademicStanding);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Bây giờ hãy chạy ứng dụng của bạn và bạn sẽ thấy kết quả sau trên cửa sổ bảng điều khiển của mình.
Fetch the complete list again
1 Allan Bommer Excellent
2 Jerry Lewis Good
Bây giờ chúng ta hãy xem xét cơ sở dữ liệu bằng cách nhấp chuột phải vào Bảng Sinh viên.
Chọn Xem Dữ liệu và bạn sẽ thấy hai bản ghi trong bảng sinh viên như được hiển thị trong ảnh chụp màn hình sau.
Bạn có thể thấy rằng hai bản ghi được thêm vào và Allan có AcademicStanding 0 và Jerry có AcademicStanding 1. Điều này là do trong .Net, giá trị liệt kê đầu tiên theo mặc định có 0, điều này là Tuyệt vời nếu bạn nhìn vào StudentAcademicStanding. Trong khi đó, trong tệp Student.cs Tốt là tệp thứ hai, vì vậy nó có giá trị là 1.
Trong chương này, chúng ta sẽ xem xét cấu hình NHibernate. Chúng tôi có nhiều cách khác nhau để có thể cấu hình NHibernate. Nó chia thành hai nhóm chính
- Cấu hình dựa trên XML
- Cấu hình dựa trên mã
Cấu hình dựa trên mã
Cấu hình dựa trên mã được tích hợp trong NHibernate. Nó đã được giới thiệu xung quanh NHibernate 3 và chúng tôi đã sử dụng cấu hình cơ sở mã cho đến nay.
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
Tất cả các cấu hình được chỉ định trong mã C #. Bạn có thể thấy ở đây rằng chúng tôi đã có đối tượng cấu hình mới và sau đó chúng tôi sử dụngloquacious configurationđã được giới thiệu với NHibernate 3.1 để cấu hình cơ sở dữ liệu. Chúng tôi đang sử dụng chuỗi kết nối nào, cơ sở dữ liệu nào chúng tôi đang kết nối và phương ngữ sẽ sử dụng. Chúng tôi cũng thêm trực tiếp tổ hợp ánh xạ của mình vào đây.
Cấu hình dựa trên XML
Nếu bạn đang sử dụng cấu hình dựa trên XML, bạn có thể sử dụng hibernate.cfg.xml , chỉ là một tệp xml độc lập sử dụng lược đồ NHibernate hoặc bạn có thể nhúng cấu hình NHibernate cụ thể đó vào bên trong ứng dụng của mình hoặc web.cfg. Tên hibernate.cfg.xml là theo mặc định, nhưng chúng ta cũng có thể sử dụng tên tùy ý cho tệp xml đó.
Hãy xem xét cấu hình dựa trên XML bằng cách thêm một tệp xml mới vào dự án NHibernateDemoApp và gọi nó là hibernate.cfg.xml.
Nhập thông tin sau vào tệp hibernate.cfg.xml.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2">
<session-factory>
<property name = "connection.connection_string">
Data Source = asia13797\\sqlexpress;
Initial Catalog = NHibernateDemoDB;
Integrated Security = True;
Connect Timeout = 15;
Encrypt = False;
TrustServerCertificate = False;
ApplicationIntent = ReadWrite;
MultiSubnetFailover = False;
</property>
<property name = "connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name = "dialect">
NHibernate.Dialect.MsSql2008Dialect
</property>
<mapping assembly = "NHibernateDemoApp"/>
</session-factory>
</hibernate-configuration>
Như bạn có thể thấy trong tệp xml ở trên, chúng tôi đã chỉ định cấu hình tương tự như đã đề cập trong C #.
Bây giờ, hãy bình luận về cấu hình này từ tệp Program.cs và chỉ cần gọi Configure() phương pháp này sẽ tải hibernate.cfg.xml như hình bên dưới.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
//cfg.DataBaseIntegration(x =>
//{
// x.ConnectionString = "Data Source = asia13797;\\sqlexpress
Initial Catalog = NHibernateDemoDB;
Integrated Security = True;
Connect Timeout = 15;
Encrypt =False;
TrustServerCertificate = False;
ApplicationIntent = ReadWrite;
MultiSubnetFailover = False";
// x.Driver<SqlClientDriver>();
// x.Dialect<MsSql2008Dialect>();
// x.LogSqlInConsole = true;
//});
//cfg.AddAssembly(Assembly.GetExecutingAssembly());
cfg.Configure();
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
student.FirstName, student.LastName, student.AcademicStanding);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Hãy chạy lại ứng dụng của bạn và bạn sẽ thấy kết quả tương tự.
Fetch the complete list again
1 Allan Bommer Excellent
2 Jerry Lewis Good
Trong chương này, chúng tôi sẽ trình bày cách ghi đè cấu hình NHibernate. Chỉ có một số điều bạn cần lưu ý.
Trước hết, cấu hình trong NHibernate là phụ gia.
Vì vậy, bạn không chỉ phải sử dụng một tệp xml duy nhất hoặc bạn không chỉ phải sử dụng cấu hình dựa trên mã hoặc NHibernate thông thạo.
Bạn có thể trộn và kết hợp tất cả các phương pháp này tùy thuộc vào cách bạn muốn định cấu hình ứng dụng của mình.
Điểm quan trọng cần nhớ là cấu hình cuối cùng sẽ thắng.
Trong ví dụ sau, bạn có thể thấy rằng chúng tôi tạo đối tượng cấu hình của mình, định cấu hình nó bằng cấu hình dựa trên mã và cuối cùng gọi cfg.configure() phương thức này tải tệp hibernate.cfg.xml.
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.Configure();
Vì vậy, bất kỳ thứ gì bên trong hibernate.cfg.xml sẽ ghi đè cài đặt được đặt bởi cấu hình dựa trên mã.
Bằng cách đảo ngược hai quy trình này, chúng tôi có thể có các giá trị mặc định bên trong hibernate.cfg.xml và sau đó thực hiện ghi đè của chúng tôi bên trong cấu hình dựa trên mã.
Không có gì loại trừ nếu bạn đang sử dụng cấu hình dựa trên mã và cũng không có gì ngăn cản bạn sử dụng tệp hibernate.cfg.xml.
Hãy xem một ví dụ đơn giản, trong đó chúng ta sẽ ghi đè cấu hình bằng cách sử dụng hỗn hợp cấu hình dựa trên xml và dựa trên mã.
Hãy cũng di chuyển chuỗi kết nối đến app.config tệp bằng cách sử dụng mã sau.
<?xml version = "1.0" encoding = "utf-8" ?>
<configuration>
<startup>
<supportedRuntime version = "v4.0" sku = ".NETFramework,Version = v4.5" />
</startup>
<connectionStrings>
<add name = "default" connectionString = "Data Source =
asia13797\\sqlexpress;
Initial Catalog = NHibernateDemoDB;
Integrated Security = True;
Connect Timeout = 15;
Encrypt = False;
TrustServerCertificate = False;
ApplicationIntent = ReadWrite;
MultiSubnetFailover = False"/>
</connectionStrings>
</configuration>
Chuỗi kết nối đang ở một số app.configtệp có tên mặc định. Bây giờ, chúng ta cần đề cập đến tên mặc định trong tệp hibernate.cfg.xml thay vì chuỗi kết nối.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2">
<session-factory>
<property name = "connection.connection_string">default</property>
<property name = "connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name = "dialect">
NHibernate.Dialect.MsSql2008Dialect
</property>
<mapping assembly = "NHibernateDemoApp"/>
</session-factory>
</hibernate-configuration>
Hãy nhận xét về phần chuỗi kết nối, trình điều khiển và phần phương ngữ từ cấu hình dựa trên mã, vì chương trình sẽ đọc nó từ tệp hibernate.cfg.xml và LogSqlInConsole một phần sẽ vẫn nằm trong cấu hình dựa trên mã.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { //x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
//x.Driver<SqlClientDriver>();
//x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.Configure();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
student.FirstName, student.LastName, student.AcademicStanding);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Bây giờ khi bạn chạy ứng dụng, bạn sẽ thấy rằng chương trình đã đọc nhật ký từ cấu hình dựa trên mã và cấu hình khác từ tệp hibernate.cfg.xml.
NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,
this_.FirstMidName as FirstMid3_0_0_, this_.AcademicStanding as Academic4_0_0_ FROM
Student this_
Fetch the complete list again
1 Allan Bommer Excellent
2 Jerry Lewis Good
Vì vậy, bây giờ chúng tôi đã có một số cấu hình bên trong hibernate.cfg.xml , một số trong số đó nằm bên trong cấu hình dựa trên mã và tùy thuộc vào thứ tự gọi dựa trên mã so với configure(), chúng ta có thể thay đổi cái nào trong số chúng sẽ ghi đè cái khác.
Trong chương này, chúng tôi sẽ đề cập đến cập nhật kích thước hàng loạt. Kích thước lô cho phép bạncontrol the number of updates đi một vòng duy nhất đến cơ sở dữ liệu của bạn để biết các cơ sở dữ liệu được hỗ trợ.
Kích thước lô cập nhật đã được đặt mặc định kể từ NHibernate 3.2.
Nhưng nếu bạn đang sử dụng phiên bản cũ hơn hoặc cần điều chỉnh ứng dụng NHibernate của mình, bạn nên xem kích thước lô cập nhật, đây là một tham số rất hữu ích có thể được sử dụng để điều chỉnh hiệu suất của NHibernate.
Trên thực tế, kích thước hàng loạt kiểm soát số lượng chèn để đẩy ra trong một nhóm vào cơ sở dữ liệu.
Hiện tại, chỉ SQL Server và Oracle hỗ trợ tùy chọn này vì nhà cung cấp cơ sở dữ liệu bên dưới cần hỗ trợ lô truy vấn.
Hãy xem một ví dụ đơn giản trong đó chúng tôi đã đặt kích thước lô thành 10 sẽ chèn 10 bản ghi trong một tập hợp.
cfg.DataBaseIntegration(x => {
x.ConnectionString = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
Đây là cách thực hiện hoàn chỉnh, trong đó 25 bản ghi sẽ được thêm vào cơ sở dữ liệu.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver>SqlClientDriver<();
x.Dialect>MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
//cfg.Configure();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
for (int i = 0; i < 25; i++) {
var student = new Student {
ID = 100+i,
FirstName = "FirstName"+i.ToString(),
LastName = "LastName" + i.ToString(),
AcademicStanding = StudentAcademicStanding.Good
};
session.Save(student);
}
tx.Commit();
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,student.FirstName,
student.LastName, student.AcademicStanding);
}
}
Console.ReadLine();
}
}
}
}
Bây giờ hãy chạy ứng dụng của bạn và bạn thấy tất cả các bản cập nhật đó đang chuyển sang hồ sơ NHibernate. Chúng tôi có 26 chuyến đi vòng quanh cơ sở dữ liệu 25 để chèn và một lần truy xuất danh sách học sinh.
Bây giờ, tại sao lại như vậy? Lý do là vì NHibernate cần làm mộtselect scope identity vì chúng tôi đang sử dụng chiến lược tạo mã nhận dạng gốc trong tệp ánh xạ cho ID như được hiển thị trong mã sau.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemoApp"
namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
<property name = "AcademicStanding"/>
</class>
</hibernate-mapping>
Vì vậy, chúng ta cần sử dụng một phương pháp khác, chẳng hạn như guid.combphương pháp. Nếu chúng ta đi đến Guid.comb, chúng ta cần chuyển đến khách hàng của mình và thay đổi nó thànhguid. Vì vậy, điều đó sẽ hoạt động tốt. Bây giờ chúng ta hãy thay đổi từ bản địa thành Guid.comb bằng cách sử dụng mã sau.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly =
"NHibernateDemoApp" namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "guid.comb"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
<property name = "AcademicStanding"/>
</class>
</hibernate-mapping>
Vì vậy, đó là cơ sở dữ liệu chịu trách nhiệm tạo ra các ID đó. Cách duy nhất NHibernate có thể tìm ra ID nào đã được tạo là chọn nó ngay sau đó. Hoặc nếu chúng tôi đã tạo một loạt sinh viên, nó sẽ không thể khớp với ID của sinh viên đã được tạo.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual Guid ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual StudentAcademicStanding AcademicStanding { get; set; }
}
public enum StudentAcademicStanding {
Excellent,
Good,
Fair,
Poor,
Terrible
}
}
Chúng tôi chỉ cần cập nhật cơ sở dữ liệu của mình. Hãy thả bảng sinh viên và tạo một bảng mới bằng cách chỉ định truy vấn sau, vì vậy hãy truy cập SQL Server Object Explorer và nhấp chuột phải vào cơ sở dữ liệu và chọnNew Query… Lựa chọn.
Nó sẽ mở trình soạn thảo truy vấn và sau đó chỉ định truy vấn sau.
DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] (
-- [ID] INT IDENTITY (1, 1) NOT NULL,
[ID] UNIQUEIDENTIFIER NOT NULL,
[LastName] NVARCHAR (MAX) NULL,
[FirstMidName] NVARCHAR (MAX) NULL,
[AcademicStanding] NCHAR(10) NULL,
CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC)
);
Truy vấn này trước tiên sẽ xóa bảng sinh viên hiện có và sau đó tạo một bảng mới. Như bạn có thể thấy rằng chúng tôi đã sử dụngUNIQUEIDENTIFIER thay vì sử dụng khóa chính số nguyên làm ID.
Thực hiện truy vấn này và sau đó đi đến Designer view và bạn sẽ thấy rằng bây giờ ID được tạo với một mã định danh duy nhất như được hiển thị trong hình ảnh sau đây.
Bây giờ chúng ta cần xóa ID khỏi tệp program.cs trong khi chèn dữ liệu, vì bây giờ nó sẽ tạo guids cho nó tự động.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
//cfg.Configure();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
for (int i = 0; i > 25; i++) {
var student = new Student {
FirstName = "FirstName"+i.ToString(),
LastName = "LastName" + i.ToString(),
AcademicStanding = StudentAcademicStanding.Good
};
session.Save(student);
}
tx.Commit();
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
student.FirstName,student.LastName, student.AcademicStanding);
}
}
Console.ReadLine();
}
}
}
}
Bây giờ hãy chạy lại ứng dụng và xem hồ sơ NHibernate. Giờ đây, hồ sơ NHibernate thay vì thực hiện 26 chuyến khứ hồi sẽ chỉ tạo ra bốn chuyến.
Nó được chèn mười hàng vào bảng, sau đó là mười hàng khác, và sau đó là năm hàng còn lại. Và sau khi commit, nó đã chèn thêm một cái nữa để lấy tất cả các bản ghi.
Vì vậy, nó chia nó thành các nhóm mười, tốt nhất có thể.
Vì vậy, nếu bạn đang thực hiện nhiều lần chèn, điều này có thể cải thiện đáng kể hiệu suất chèn trong ứng dụng của bạn, vì bạn có thể bổ sung hàng loạt.
Điều này là do NHibernate tự chỉ định các guid đó bằng cách sử dụng guid.comb thuật toán và nó không cần phải dựa vào cơ sở dữ liệu để làm điều này.
Vì vậy, sử dụng kích thước lô là một cách tuyệt vời để điều chỉnh nó.
Trong chương này, chúng tôi sẽ trình bày về cách cachinghoạt động trong các ứng dụng NHibernate. Nó có hỗ trợ tích hợp cho bộ nhớ đệm. Nó trông có vẻ như là một tính năng đơn giản, nhưng trên thực tế, nó là một trong những tính năng phức tạp nhất. Chúng ta sẽ bắt đầu với Bộ nhớ đệm cấp độ đầu tiên.
Bộ nhớ đệm cấp độ đầu tiên
Cơ chế bộ nhớ cache này được kích hoạt theo mặc định trong NHibernate và chúng tôi không cần phải làm gì để làm việc với bộ nhớ cache. Để hiểu điều này, chúng ta hãy xem xét một ví dụ đơn giản, như bạn có thể thấy rằng chúng tôi có hai bản ghi trong cơ sở dữ liệu của mình.
Bây giờ trong ví dụ này, chúng tôi sẽ truy xuất sinh viên có ID là 1 và chúng tôi sẽ sử dụng cùng một truy vấn phiên hai lần như được hiển thị trong đoạn mã sau.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cache;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
//cfg.Configure();
cfg.Cache(c => {
c.UseMinimalPuts = true;
c.UseQueryCache = true;
});
cfg.SessionFactory().Caching .Through<HashtableCacheProvider>()
.WithDefaultExpiration(1440);
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()){
using (var tx = session.BeginTransaction()) {
var studentUsingTheFirstQuery = session.Get<Student>(1);
var studentUsingTheSecondQuery = session.Get<Student>(1);
}
Console.ReadLine();
}
}
}
}
Bây giờ, hãy chạy ứng dụng này và xem kết quả trong NHibernate Profiler.
Bạn sẽ ngạc nhiên khi thấy NHibernate chỉ kích hoạt một truy vấn. Đây là cách NHibernate sử dụng bộ nhớ cache cấp đầu tiên. Khi truy vấn đầu tiên được thực thi, sau đó NHibernate đã lưu vào bộ nhớ đệm Sinh viên có ID = 1 trong bộ đệm cấp đầu tiên của nó.
Vì vậy, khi truy vấn thứ hai được thực thi thì NHibernate trước tiên sẽ tìm kiếm thực thể Student trong bộ đệm ẩn cấp đầu tiên với ID = 1, nếu nó tìm thấy thực thể đó, thì NHibernate biết rằng, không cần phải kích hoạt một truy vấn khác để lấy lại cùng một đối tượng nhân viên. .
Trong chương này, chúng ta sẽ nói về các thành phần ánh xạ. Trong NHibernate,component is a value object. Nó không có một bản sắc riêng của nó.
Ví dụ về điều này sẽ là một vật thể tiền, một chiếc ví hoặc một chiếc ví có thể có tiền trong đó, nhưng danh tính chính xác của số tiền đó là không liên quan.
Nó không có khóa chính của riêng nó, nhưng bản thân các thành phần luôn tồn tại trong cùng một bảng với đối tượng sở hữu.
Hãy xem một ví dụ đơn giản trong đó một sinh viên có Địa chỉ, là đối tượng của Location class Liên kết với nó.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual int ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual StudentAcademicStanding AcademicStanding { get; set; }
public virtual Location Address { get; set; }
}
public class Location {
public virtual string Street { get; set; }
public virtual string City { get; set; }
public virtual string Province { get; set; }
public virtual string Country { get; set; }
}
public enum StudentAcademicStanding {
Excellent,
Good,
Fair,
Poor,
Terrible
}
}
Bây giờ, chúng ta cũng cần cập nhật cơ sở dữ liệu bằng cách thực hiện truy vấn sau, truy vấn này trước tiên sẽ thả bảng Sinh viên và sau đó tạo một bảng mới cũng sẽ chứa một cột cho lớp Vị trí.
DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[LastName] NVARCHAR (MAX) NULL,
[FirstMidName] NVARCHAR (MAX) NULL,
[AcademicStanding] NCHAR(10) NULL,
[Street] NVARCHAR (100) NULL,
[City] NVARCHAR (100) NULL,
[Province] NVARCHAR (100) NULL,
[Country] NVARCHAR (100) NULL,
CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC)
);
Bây giờ để ánh xạ những cột không trực tiếp là một phần của lớp Sinh viên, nhưng chúng là thuộc tính của lớp Vị trí và đối tượng lớp Vị trí được xác định trong lớp sinh viên. Chúng tôi cần một thành phần để ánh xạ nó một cách chính xác. Hãy tạo một thành phần trongstudent.hbm.xml tệp như được hiển thị trong mã sau.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
<property name = "AcademicStanding"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
</class>
</hibernate-mapping>
Thành phần này là Địa chỉ và nó có các thuộc tính khác nhau trên đó. Với thông tin này, NHibernate hiện có đủ để nó thực sự có thể lập bản đồ này.
Bây giờ đây là tệp Program.cs trong đó một đối tượng sinh viên mới được tạo và khởi tạo, sau đó được lưu vào cơ sở dữ liệu. Sau đó, nó sẽ lấy danh sách từ cơ sở dữ liệu.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cache;
using NHibernate.Caches.SysCache;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var student1 = new Student {
ID = 1,
FirstName = "Allan",
LastName = "Bommer",
AcademicStanding = StudentAcademicStanding.Poor,
Address = new Location {
Street = "123 Street",
City = "Lahore",
Province = "Punjab",
Country = "Pakistan"
}
};
session.Save(student1);
tx.Commit();
var students = session.Query<Student>().ToList<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3} \t{4} \t{5} \t{6} \t{7}",
student.ID,
student.FirstName,
student.LastName,
student.AcademicStanding,
student.Address.Street,
student.Address.City,
student.Address.Province,
student.Address.Country
);
}
}
Console.ReadLine();
}
}
}
}
Bây giờ chúng ta có thể chạy ứng dụng này và NHibernate có thể lưu các giá trị đó vào cơ sở dữ liệu. Khi bạn chạy ứng dụng, bạn sẽ thấy kết quả sau.
Fetch the complete list again
2 Allan Bommer Poor 123 Street Lahore Punjab Pakistan
Đây là các giá trị trong cơ sở dữ liệu.
Các thành phần cho phép chúng tôi tách các cột trong bảng cơ sở dữ liệu thành lớp riêng biệt của chúng.
Điều khác cần chú ý ở đây là bởi vì Vị trí là một lớp, nó không phải là một thực thể.
Nó là một đối tượng kiểu giá trị và nó không có khóa chính của riêng mình.
Nó được lưu trong cùng một bảng với Student chứa nó.
Đó là lý do tại sao chúng tôi sử dụng thành phần ở đây.
Điều này cho phép rất nhiều sự linh hoạt để thay đổi lớp lớp của chúng ta, cách các lớp của chúng ta được định nghĩa so với cách cơ sở dữ liệu của chúng ta được bố trí.
Trong chương này, chúng ta sẽ xem xét các mối quan hệ trong NHibernate. Hãy chuyển sự chú ý của chúng ta đến cách chúng ta có thể hiểu các mối quan hệ trong NHibernate. Cách dễ nhất là nghĩ về các mối quan hệ từ góc độ cơ sở dữ liệu.
Trước tiên, chúng tôi sẽ tạo một ứng dụng mới, trong đó chúng tôi sẽ tạo một số mối quan hệ giữa khách hàng và thực thể đặt hàng.
Mối quan hệ đầu tiên chúng ta sẽ xem xét là mối quan hệ sưu tập cổ điển.
Chúng tôi có một khách hàng với một bộ sưu tập các đơn đặt hàng.
Đây là mối quan hệ một-nhiều và nó được thể hiện trong cơ sở dữ liệu bằng 2 bảng và có một ID khách hàng trên bảng đơn đặt hàng và chúng tôi có một mối quan hệ khóa ngoài với khách hàng.
Đầu tiên chúng ta cần tạo một cơ sở dữ liệu và hai bảng Khách hàng và Đơn hàng. Bạn có thể tạo điều này bằng cách chỉ định truy vấn sau trong SQL Server Explorer.
USE [master]
GO
CREATE DATABASE [NHibernateDemo]
GO
USE [NHibernateDemo]
GO
CREATE TABLE [dbo].[Customer](
[Id] [uniqueidentifier] NOT NULL,
[FirstName] [nvarchar](100) NOT NULL,
[LastName] [nvarchar](100) NOT NULL,
[Points] [int] NULL, [HasGoldStatus] [bit] NULL,
[MemberSince] [date] NULL,
[CreditRating] [nchar](20) NULL,
[AverageRating] [decimal](18, 4) NULL,
[Street] [nvarchar](100) NULL,
[City] [nvarchar](100) NULL,
[Province] [nvarchar](100) NULL,
[Country] [nvarchar](100) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
)
GO
CREATE TABLE [dbo].[Order](
[Id] [uniqueidentifier] NOT NULL,
[CustomerId] [uniqueidentifier] NULL,
[Ordered] [datetime] NULL,
[Shipped] [datetime] NULL,
[Street] [nvarchar](100) NULL,
[City] [nvarchar](100) NULL,
[Province] [nvarchar](100) NULL,
[Country] [nvarchar](100) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
)
GO
Nó sẽ tạo ra hai bảng trong cơ sở dữ liệu. Hình ảnh sau đây cho thấy Bảng Khách hàng.
Hình ảnh sau đây cho thấy Bảng đơn hàng trong đó bạn có thể thấy mối quan hệ khóa ngoại trở lại khách hàng.
Chúng ta cần xác định chuỗi kết nối trong app.config , đây là việc triển khai tệp app.config.
<?xml version = "1.0" encoding = "utf-8" ?>
<configuration>
<connectionStrings>
<add name = "default" connectionString = "Data Source =
(localdb)\MSSQLLocalDB;Initial Catalog = NHibernateDemo;Integrated Security =
True;Connect Timeout = 30;Encrypt = False;TrustServerCertificate = False;
ApplicationIntent = ReadWrite;MultiSubnetFailover = False"/>
</connectionStrings>
</configuration>
Để cài đặt NHibernate trong ứng dụng của bạn, hãy chạy lệnh sau trong cửa sổ NuGet Manager Console.
install-package NHibernate
Để định cấu hình NHibernate, chúng ta cần xác định cấu hình trong hibernate.cfg.xml tệp như được hiển thị trong mã sau.
<xml version = "1.0" encoding = "utf-8" ?>
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2">
<session-factory>
<property name = "connection.connection_string_name">default</property>
<property name = "connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name = "dialect">
NHibernate.Dialect.MsSql2008Dialect
</property>
<property name = "show_sql">true</property>
</session-factory>
</hibernate-configuration>
Trong ví dụ này, chúng ta sẽ làm việc với hai lớp miền, Khách hàng và Đơn hàng.
Đây là triển khai tệp Customer.cs trong đó chúng ta có hai lớp, một là lớp Khách hàng và lớp khác là lớp Vị trí mà đối tượng được sử dụng làm địa chỉ trong lớp Khách hàng.
using System;
using System.Text;
using Iesi.Collections.Generic;
namespace NHibernateDemo {
public class Customer {
public Customer() {
MemberSince = DateTime.UtcNow;
Orders = new HashedSet<Order>();
}
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual Location Address { get; set; }
public virtual ISet<Order> Orders { get; set; }
public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
public override string ToString() {
var result = new StringBuilder();
result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
{4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
{8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
CreditRating, MemberSince.Kind, AverageRating);
result.AppendLine("\tOrders:");
foreach(var order in Orders) {
result.AppendLine("\t\t" + order);
}
return result.ToString();
}
}
public class Location {
public virtual string Street { get; set; }
public virtual string City { get; set; }
public virtual string Province { get; set; }
public virtual string Country { get; set; }
}
public enum CustomerCreditRating {
Excellent,
VeryVeryGood,
VeryGood,
Good,
Neutral,
Poor,
Terrible
}
}
Đây là tệp ánh xạ Customer.hbm.xml trong đó lớp Khách hàng được ánh xạ tới bảng Khách hàng.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
</class>
</hibernate-mapping>
Chúng tôi cũng có một Lớp đặt hàng và đây là việc triển khai Order.cs tập tin.
using System; using Iesi.Collections.Generic;
namespace NHibernateDemo {
public class Order {
public virtual Guid Id { get; set; }
public virtual DateTime Ordered { get; set; }
public virtual DateTime? Shipped { get; set; }
public virtual Location ShipTo { get; set; }
public virtual Customer Customer { get; set; }
public override string ToString() {
return string.Format("Order Id: {0}", Id);
}
}
}
Mối quan hệ nhiều-một
Chúng ta cũng cần ánh xạ lớp Order tới bảng Order trong cơ sở dữ liệu, vì vậy đây là việc triển khai Order.hbm.xml tập tin.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Order" table = "`Order`">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "Ordered"/>
<property name = "Shipped"/>
<component name = "ShipTo">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<!--<many-to-one name = "Customer" column = "CustomerId" cascade =
"save-update"/>-->
</class>
</hibernate-mapping>
Mối quan hệ một-nhiều
Ở đây, chúng ta sẽ xem xét mối quan hệ một-nhiều, trong trường hợp này là giữa khách hàng và đơn đặt hàng. Chúng tôi đã có khách hàng của mình ở đây, chúng tôi đang tạo một khách hàng mới và bạn có thể thấy rằng bộ sưu tập được khởi tạo với cặp đơn đặt hàng sau.
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points = 100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order {
Ordered = DateTime.Now
};
customer.AddOrder(order1);
var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2);
return customer;
}
Vì vậy chúng ta sẽ tạo một khách hàng mới rồi lưu lại, sau khi lưu xong chúng ta tìm ID rồi tải lại trong một phiên khác ở phương thức Main như trong chương trình sau.
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
Đây là đầy đủ Program.cs triển khai tệp.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
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();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points = 100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order {
Ordered = DateTime.Now
};
customer.AddOrder(order1);
var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2);
return customer;
}
private static Location CreateLocation() {
return new Location {
Street = "123 Somewhere Avenue",
City = "Nowhere",
Province = "Alberta",
Country = "Canada"
};
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x =&ht; {
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;
}
}
}
Khi bạn chạy ứng dụng này, bạn sẽ thấy kết quả sau.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (9b0fcf10-83f6-4f39-bda5-a5b800ede2ba)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Press <ENTER> to exit...
Như bạn thấy, ban đầu khách hàng có 2 đơn hàng, nhưng khi chúng tôi tải lại thì không thấy đơn hàng nào. Nếu bạn nhìn vàocustomer.hbm.xml, bạn có thể thấy ở đây rằng chúng tôi không lập bản đồ thu thập đơn đặt hàng thực tế. Vì vậy NHibernate không biết gì về nó. Hãy tiếp tục và thêm nó.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemo" namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Đây là một tập hợp và tên của tập hợp này là 'Đơn hàng', được lưu trữ trong một bảng được gọi là đơn hàng. Chúng ta cần chỉ định một khóa là tên của khóa ngoại hoặc để tìm đơn đặt hàng. Các đơn đặt hàng này được xác định hoặc thuộc về khách hàng thông qua ID khách hàng. Và sau đó tôi phải lưu ý rằng đây là mối quan hệ một-nhiều và nó là với lớp thứ tự.
Chúng tôi cũng cần thay đổi một chút phương thức Chính bằng cách lưu các đơn đặt hàng mới của khách hàng vào cơ sở dữ liệu cũng như được hiển thị trong chương trình sau.
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
foreach (var order in newCustomer.Orders) {
session.Save(order);
}
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var reloaded = session.Load<Customer>(id);
Console.WriteLine("The orders were ordered by: ");
foreach (var order in reloaded.Orders) {
Console.WriteLine(order.Customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit..."); Console.ReadLine();
}
Chúng tôi cũng đã chỉ định khách hàng nào đã đặt hàng sản phẩm cụ thể đó. Vì vậy, chúng ta cần tạo mối quan hệ nhiều-một để liên kết lại đơn hàng đó với khách hàng đó.
Vì vậy, chúng ta hãy đi vào Order.hbm.xml và thêm nhiều-một, sau đó đặt tên trường khách hàng và cột có ID khách hàng.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Order" table = "`Order`">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "Ordered"/>
<property name = "Shipped"/>
<component name = "ShipTo">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<many-to-one name = "Customer" column = "CustomerId"/>
</class>
</hibernate-mapping>
Hãy chạy lại ứng dụng này và bây giờ bạn sẽ thấy kết quả sau.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3
The orders were ordered by:
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3
Press <ENTER> to exit...
Trong chương này, chúng tôi sẽ trình bày cách biểu diễn các tập hợp. Có nhiều loại bộ sưu tập khác nhau mà chúng tôi có thể sử dụng trong NHibernate, chẳng hạn như -
- Lists
- Sets
- Bags
Bây giờ, từ góc độ .NET, chúng ta thường xử lý các danh sách hoặc như các cấu trúc dữ liệu, danh sách, từ điển rất đơn giản. .NET không có nhiều loại tập hợp khác nhau. Vậy tại sao NHibernate lại cần tất cả các loại khác nhau này? Nó thực sự quay trở lại cơ sở dữ liệu.
Danh sách
Danh sách là một tập hợp có thứ tự các phần tử không nhất thiết phải là duy nhất.
Chúng tôi có thể lập bản đồ này bằng cách sử dụng IList <T>.
Vì vậy, mặc dù thông thường chúng ta có thể có một danh sách các địa chỉ và từ quan điểm ứng dụng, chúng ta biết rằng các phần tử là duy nhất, không có gì trong danh sách ngăn chúng ta chèn các phần tử trùng lặp vào danh sách đó.
Bộ
Tập hợp là một tập hợp các phần tử duy nhất không có thứ tự. Nếu bạn cố gắng chèn 2 phần tử trùng lặp vào một tập hợp, nó sẽ tạo ra một ngoại lệ.
Không có gì cụ thể trong NHibernate về nó.
Đó chỉ là một cách thuận tiện để có một triển khai tập hợp chung. Nếu bạn đang sử dụng .NET 4, bạn có thể sử dụngHashSet <T> để đại diện cho những điều này, nhưng trong hầu hết các ứng dụng NHibernate, chúng tôi khẳng định đây là một ISet.
Nó là một không có thứ tự, nếu bạn kéo lại một danh sách các địa chỉ từ cơ sở dữ liệu hoặc một danh sách các đơn hàng, bạn sẽ không biết chúng đến theo thứ tự nào trừ khi bạn đưa vào một mệnh đề Order by cụ thể.
Vì vậy, nói chung, dữ liệu bạn đang lấy lại từ cơ sở dữ liệu là các tập hợp.
Chúng là tập hợp các phần tử duy nhất không có thứ tự.
Túi
Một tập hợp phổ biến khác mà chúng ta sẽ thấy trong thế giới cơ sở dữ liệu là một túi, giống như một tập hợp ngoại trừ nó có thể có các phần tử trùng lặp.
Trong thế giới .NET, chúng tôi đại diện cho điều này bởi một IList.
Bộ có lẽ là phổ biến nhất, nhưng bạn sẽ thấy danh sách và túi cũng tùy thuộc vào ứng dụng của bạn. Chúng ta hãy xem xét một bên dướicustomer.hbm.xml từ chương cuối cùng trong đó Đặt lệnh được xác định.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Như bạn có thể thấy, chúng tôi đã ánh xạ tập hợp các đơn đặt hàng thành một tập hợp. Hãy nhớ rằng một tập hợp là một tập hợp không có thứ tự của các phần tử duy nhất.
Bây giờ, nếu bạn nhìn vào lớp Khách hàng, bạn sẽ thấy thuộc tính Đơn hàng được định nghĩa bằng ISet như được hiển thị trong chương trình sau.
public virtual ISet<Order> Orders { get; set; }
Bây giờ khi ứng dụng này được chạy, bạn sẽ thấy kết quả sau.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
The orders were ordered by:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
Press <ENTER> to exit...
Nếu các mục trong bộ sưu tập không cần phải là duy nhất, nếu bạn có thể có nhiều đơn đặt hàng với cùng một khóa chính xảy ra nhiều lần trong bộ sưu tập này, thì tốt hơn nó sẽ được ánh xạ dưới dạng một túi như thể hiện trong chương trình sau.
<bag name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</bag>
Bây giờ, nếu bạn chạy ứng dụng này, bạn sẽ nhận được một ngoại lệ vì nếu chúng ta xem xét lớp khách hàng, bạn sẽ nhận thấy rằng các đơn đặt hàng được đánh dấu là ISet trong mã C #.
Vì vậy, chúng ta cũng sẽ cần thay đổi điều này thành IList và sau đó ở đây, chúng ta sẽ cần thay đổi từ HashSet thành Danh sách trong phương thức khởi tạo.
public class Customer {
public Customer() {
MemberSince = DateTime.UtcNow;
Orders = new List<Order>();
}
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual Location Address { get; set; }
public virtual IList<Order> Orders { get; set; }
public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
public override string ToString() {
var result = new StringBuilder();
result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
{4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
{8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
CreditRating, MemberSince.Kind, AverageRating); result.AppendLine("\tOrders:");
foreach(var order in Orders) {
result.AppendLine("\t\t" + order);
}
return result.ToString();
}
}
Khi bạn chạy ứng dụng, bạn sẽ thấy hành vi tương tự. Nhưng, bây giờ chúng ta có thể có một đơn đặt hàng xảy ra nhiều lần trong cùng một bộ sưu tập.
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
The orders were ordered by:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
Press <ENTER> to exit...
Trong chương này, chúng tôi sẽ trình bày cách sử dụng tính năng Cascade. Nếu bạn có một tập hợp hoặc một tập hợp các mặt hàng hoặc mối quan hệ giữa hai lớp như khách hàng và đơn hàng của chúng tôi và có mối quan hệ khóa ngoài. Nếu chúng tôi xóa khách hàng theo mặc định, NHibernate không thực hiện bất kỳ điều gì đối với các đối tượng con, vì vậy những đối tượng thuộc về khách hàng đó và chúng tôi có thể là đơn đặt hàng mồ côi.
Chúng tôi cũng có thể vi phạm các ràng buộc khóa ngoại, vì vậy chúng tôi có thể sử dụng khái niệm về các tầng.
Theo mặc định, NHibernate không phân tầng các hoạt động với các đối tượng con.
Lý do là bạn có thể có những mối quan hệ chẳng hạn như một khách hàng có địa chỉ giao hàng mặc định và địa chỉ giao hàng đó được chia sẻ với nhiều khách hàng khác nhau.
Vì vậy, bạn sẽ không muốn kết nối mối quan hệ đó nhất thiết vì những khách hàng khác vẫn đang đề cập đến nó.
Vì vậy, toàn bộ khái niệm về thác là để cho NHibernate biết cách xử lý các thực thể con của nó.
Có các tùy chọn khác nhau để xếp tầng, như sau:
none - là mặc định và nó có nghĩa là không xếp tầng.
all - sẽ lưu, cập nhật và xóa theo tầng.
save-update - nó sẽ phân tầng, lưu và cập nhật.
delete - nó sẽ xóa theo tầng.
all-delete-orphan - nó là một đặc biệt được sử dụng khá thường xuyên và giống với Tất cả Ngoại trừ, nếu nó tìm thấy hàng Xóa-mồ côi, nó cũng sẽ xóa những hàng đó.
Bạn có thể chỉ định giá trị mặc định trong hbm.xml , vì vậy bạn có thể cung cấp một tầng mặc định trên phần tử ánh xạ Hibernate đó hoặc bạn cũng có thể chỉ định nó cho các tập hợp và mối quan hệ cụ thể chẳng hạn như nhiều-một.
Chúng ta hãy xem xét các tầng ví dụ đơn giản, hãy khắc phục sự cố trong chương trình, trong đó chúng ta phải xếp tầng theo cách thủ công lưu vào các đơn đặt hàng như được hiển thị trong đoạn mã sau.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
foreach (var order in newCustomer.Orders) {
session.Save(order);
}
id = newCustomer.Id;
tx.Commit();
}
Trong đoạn mã trên, bạn có thể thấy rằng chúng tôi đang lưu tất cả các đơn đặt hàng cho khách hàng theo cách thủ công. Bây giờ chúng ta hãy xóa mã xếp tầng thủ công trong đó tất cả các đơn hàng được lưu.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
Chúng tôi cần chỉ định tùy chọn xếp tầng trong customer.hbm.xml.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Bây giờ, đơn đặt hàng hoàn toàn thuộc về khách hàng. Vì vậy, nếu khách hàng bị xóa khỏi cơ sở dữ liệu, ứng dụng của chúng tôi ở đây sẽ muốn xóa tất cả các đơn đặt hàng đó, bao gồm cả bất kỳ đơn hàng nào có thể đã bị bỏ sót.
Nó sẽ kết thúc việc xóa. Bằng cách đó, nó sẽ cho biết xóa khỏi bảng đơn đặt hàng, trong đó ID khách hàng bằng với khách hàng mà bạn đang xóa.
Vì vậy, bạn thực sự có thể xếp tầng các lần xóa này. Vì vậy, vớiAll, nó sẽ thực hiện lưu, cập nhật và xóa.
Bây giờ khi bạn chạy ứng dụng này, bạn sẽ thấy kết quả sau.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
Press <ENTER> to exit...
Như bạn có thể thấy rằng chúng tôi đã xóa mã khỏi chương trình xếp tầng thủ công và ứng dụng của chúng tôi vẫn đang hoạt động.
Vì vậy, tùy thuộc vào mối quan hệ của bạn, bạn có thể muốn xếp tầng những thứ đó. Bây giờ, chúng ta hãy xem xét một mối quan hệ tầng khác nhau. Hãy đi đếnOrder.hbm.xml và chúng tôi có thể phân tầng mối quan hệ nhiều-một đó.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Order" table = "`Order`">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "Ordered"/>
<property name = "Shipped"/>
<component name = "ShipTo">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<many-to-one name = "Customer" column = "CustomerId" cascade = "save-update"/>
</class>
</hibernate-mapping>
Vì vậy, nếu chúng tôi tạo một đơn đặt hàng mới và có một khách hàng mới gắn liền với đơn đặt hàng đó và chúng tôi nói rằng, hãy lưu đơn đặt hàng đó, chúng tôi có thể muốn xếp tầng. Nhưng có một điều mà chúng tôi có lẽ không muốn làm là nếu một đơn hàng bị xóa sẽ xóa khách hàng tương ứng.
Vì vậy, ở đây, chúng tôi muốn thực hiện cập nhật lưu, do đó, sử dụng cập nhật lưu, nó sẽ phân tầng bất kỳ lưu hoặc cập nhật nào cho khách hàng đó. Vì vậy, nếu chúng ta có được một khách hàng mới hoặc nếu chúng ta đang thay đổi khách hàng, thì điều đó sẽ xảy ra. Nếu đó là một xóa, nó sẽ không xóa nó khỏi cơ sở dữ liệu.
Vì vậy, chạy lại ứng dụng của chúng tôi, mọi thứ vẫn hoạt động như mong đợi.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
Press <ENTER> to exit...
Bây giờ bạn nên xem xét ứng dụng của mình, hãy nhớ rằng mặc định là Không có và bạn phải suy nghĩ về các thực thể của mình và các mối quan hệ giữa chúng để xác định các tầng thích hợp cho từng thực thể cũng như từng mối quan hệ của bạn trong cơ sở dữ liệu đó.
Trong chương này, chúng tôi sẽ đề cập đến tính năng tải lười biếng. Theo mặc định, đây là một khái niệm hoàn toàn khác và NHibernate không có tính năng tải chậm, ví dụ: nếu bạn tải một khách hàng, nó sẽ không tải tất cả các đơn đặt hàng.
Bộ sưu tập đơn hàng sẽ được tải theo yêu cầu.
Bất kỳ liên kết nào, cho dù là nhiều-một hay một tập hợp đều được tải chậm theo mặc định, nó yêu cầu Open ISession.
Nếu bạn đã đóng phiên của mình hoặc nếu bạn đã thực hiện giao dịch của mình, bạn có thể nhận được một ngoại lệ tải chậm mà nó không thể kéo các đối tượng bổ sung đó vào.
Bạn phải cẩn thận về việc tải chậm và lượng dữ liệu bạn thực sự cần.
Bạn có thể tắt tính năng tải chậm cho toàn bộ liên kết hoặc bạn có thể đặt lười biếng bằng false hoặc bạn cũng có thể chỉ định chiến lược tìm nạp.
Đây là Program.cs triển khai tệp.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
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();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
Console.WriteLine("The orders were ordered by: ");
foreach (var order in reloaded.Orders) {
Console.WriteLine(order.Customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points =100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order { Ordered = DateTime.Now };
customer.AddOrder(order1);
var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2); return customer;
}
private static Location CreateLocation() {
return new Location {
Street = "123 Somewhere Avenue",
City = "Nowhere",
Province = "Alberta",
Country = "Canada"
};
}
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;
}
}
}
Để hiểu điều này, hãy chạy ứng dụng và xem qua NHibernate Profiler.
Như bạn có thể thấy rằng chúng tôi có Chọn Từ Khách hàng, được cung cấp một ID khách hàng cụ thể và sau đó chúng tôi cũng có một bảng Chọn Từ Đơn đặt hàng khác, khi nó thực sự truy cập vào bộ sưu tập của khách hàng đó.
Vì vậy, chúng tôi có 2 roundtrips đến cơ sở dữ liệu. Bây giờ, đôi khi, chúng tôi muốn tối ưu hóa điều này. Để làm điều này, chúng ta hãy đi đếncustomer.hbm.xml và thêm chiến lược tìm nạp và yêu cầu chiến lược đó thực hiện tìm nạp tham gia.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"
fetch = "join">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Như bạn có thể thấy rằng chúng tôi chưa thay đổi bất kỳ mã nào trong ứng dụng của mình, chúng tôi vừa thêm một chiến lược tìm nạp trong customer.hbm.xml. Hãy chạy lại ứng dụng này, nó vẫn hoạt động giống hệt như cũ. Hãy nhìn vào NHibernate Profiler.
Trước đây, chương trình có hai chuyến đi vòng quanh cơ sở dữ liệu, bây giờ, nó chỉ có một và đó là vì nó đang thực hiện một phép nối bên ngoài bên trái ở đây.
Chúng ta có thể thấy rằng nó đang thực hiện kết hợp bên ngoài bên trái giữa bảng khách hàng và bảng đơn hàng dựa trên ID khách hàng và do đó, nó có thể tải tất cả thông tin đó cùng một lúc.
Chúng tôi đã lưu 1 vòng vào cơ sở dữ liệu.
Mặt trái là thông tin khách hàng sẽ được sao chép trên cả hai dòng và đó là cách hoạt động của phép nối bên ngoài bên trái SQL.
Vì vậy, với chiến lược tìm nạp, chúng tôi đang lấy lại nhiều dữ liệu hơn một chút và chúng tôi đang tiết kiệm một vòng.
Bạn cũng có thể thực hiện việc này ở cấp độ truy vấn, vì vậy hãy chuyển đến Program.cs và xem ví dụ tải lại đơn giản hơn.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
//var query = from customer in session.Query<Customer>()
// select customer;
//var reloaded = query.Fetch(x => x.Orders).ToList();
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
Console.WriteLine("The orders were ordered by: ");
foreach (var order in reloaded.Orders) {
Console.WriteLine(order.Customer);
}
tx.Commit();
}
Ở đây, chúng tôi đang thực hiện tải của khách hàng. Bây giờ hãy thay đổi nó thành một truy vấn và chúng tôi sẽ sử dụng một truy vấn liên kết như được hiển thị trong đoạn mã sau.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var query = from customer in session.Query<Customer>()
where customer.Id == id select customer;
var reloaded = query.Fetch(x => x.Orders).ToList().First();
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
tx.Commit();
}
Cũng hãy xóa chiến lược tìm nạp khỏi customer.hbm.xml tập tin.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Hãy chạy lại ứng dụng này và bạn sẽ thấy kết quả sau.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (6ebacd17-f9ba-4ad8-9817-a5bb01112a5a)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 16a6596b-d56e-41c7-9681-a5bb01112a60
Order Id: d41d615b-0f21-4032-81db-a5bb01112a61
Press <ENTER> to exit...
Bây giờ chúng ta hãy nhìn vào NHibernate Profiler, bạn có thể thấy rằng chúng tôi đã có lần tìm nạp tham gia háo hức này xảy ra một lần nữa, nhưng lần này, nó dựa trên truy vấn.
Trong chương này, chúng ta sẽ đề cập đến một tính năng khác là Mối quan hệ nghịch đảo. Đó là một tùy chọn thú vị mà bạn sẽ thấy trên bộ sưu tập tỷ lệ nghịch với true và nó cũng khiến nhiều nhà phát triển bối rối. Vì vậy, chúng ta hãy nói về tùy chọn này. Để hiểu điều này, bạn thực sự phải nghĩ về mô hình quan hệ. Giả sử bạn có một liên kết hai chiều bằng cách sử dụng một khóa ngoại duy nhất.
Từ quan điểm quan hệ, bạn có một khóa ngoại, và nó đại diện cho cả khách hàng đặt hàng và đặt hàng cho khách hàng.
Từ mô hình OO, bạn có các liên kết đơn hướng bằng cách sử dụng các tham chiếu này.
Không có gì nói rằng hai liên kết đơn hướng đại diện cho cùng một liên kết hai chiều trong cơ sở dữ liệu.
Vấn đề ở đây là NHibernate không có đủ thông tin để biết rằng customer.orders và order.customer đại diện cho mối quan hệ giống nhau trong cơ sở dữ liệu.
Chúng tôi cần cung cấp inverse equals true như một gợi ý, đó là bởi vì các liên kết đơn hướng đang sử dụng cùng một dữ liệu.
Nếu chúng tôi cố gắng lưu các mối quan hệ này có 2 tham chiếu đến chúng, NHibernate sẽ cố gắng cập nhật tham chiếu đó hai lần.
Nó thực sự sẽ thực hiện thêm một vòng đối với cơ sở dữ liệu và nó cũng sẽ có 2 bản cập nhật cho khóa ngoại đó.
Giá trị nghịch đảo bằng true cho NHibernate biết nên bỏ qua mặt nào của mối quan hệ.
Khi bạn áp dụng nó cho phía bộ sưu tập và NHibernate sẽ luôn cập nhật khóa ngoại từ phía bên kia, từ phía đối tượng con.
Sau đó, chúng tôi chỉ có một bản cập nhật cho khóa ngoại đó và chúng tôi không có bản cập nhật bổ sung cho dữ liệu đó.
Điều này cho phép chúng tôi ngăn chặn các bản cập nhật trùng lặp đối với khóa ngoại và nó cũng giúp chúng tôi ngăn chặn các vi phạm khóa ngoại.
Hãy xem customer.cs trong đó bạn sẽ thấy AddOrdervà ý tưởng ở đây là bây giờ chúng ta có con trỏ quay lại này từ đơn đặt hàng trở lại khách hàng và nó cần được thiết lập. Vì vậy, khi một đơn đặt hàng được thêm vào một khách hàng, con trỏ quay lại của khách hàng đó sẽ được đặt, nếu không, nó sẽ là rỗng, vì vậy chúng ta cần điều này để giữ cho điều này được kết nối đúng cách với nhau trong biểu đồ đối tượng.
using System;
using System.Text;
using Iesi.Collections.Generic;
namespace NHibernateDemo {
public class Customer {
public Customer() {
MemberSince = DateTime.UtcNow; Orders = new HashedSet<Order>();
}
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual Location Address { get; set; }
public virtual ISet<Order> Orders { get; set; }
public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
public override string ToString() {
var result = new StringBuilder();
result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
{4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
{8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
CreditRating, MemberSince.Kind, AverageRating);
result.AppendLine("\tOrders:");
foreach(var order in Orders) {
result.AppendLine("\t\t" + order);
}
return result.ToString();
}
}
public class Location {
public virtual string Street { get; set; }
public virtual string City { get; set; }
public virtual string Province { get; set; }
public virtual string Country { get; set; }
}
public enum CustomerCreditRating {
Excellent,
VeryVeryGood,
VeryGood,
Good,
Neutral,
Poor,
Terrible
}
}
Đây là Program.cs triển khai tệp.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
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();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var query = from customer in session.Query<Customer>() where
customer.Id == id select customer;
var reloaded = query.Fetch(x => x.Orders).ToList().First();
Console.WriteLine("Reloaded:"); Console.WriteLine(reloaded);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points = 100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order { Ordered = DateTime.Now };
customer.AddOrder(order1); var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2);
return customer;
}
private static Location CreateLocation() {
return new Location {
Street = "123 Somewhere Avenue",
City = "Nowhere",
Province = "Alberta",
Country = "Canada"
};
}
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;
}
}
}
Nó sẽ lưu nó vào cơ sở dữ liệu và sau đó tải lại nó. Bây giờ hãy chạy ứng dụng của bạn và mở NHibernate Profiler và xem nó thực sự đã lưu nó như thế nào.
Bạn sẽ nhận thấy rằng chúng tôi có 3 nhóm câu lệnh. Cái đầu tiên sẽ chèn khách hàng và ID của khách hàng đó là Hướng dẫn, được đánh dấu. Câu lệnh thứ hai được chèn vào bảng đơn hàng.
Bạn sẽ nhận thấy cùng một Hướng dẫn ID khách hàng được đặt trong đó, vì vậy hãy đặt khóa ngoại đó. Câu lệnh cuối cùng là bản cập nhật, sẽ cập nhật lại khóa ngoại cho cùng một id khách hàng.
Bây giờ vấn đề là khách hàng có đơn đặt hàng, và đơn đặt hàng có khách hàng, không có cách nào mà chúng tôi đã không nói với NHibernate rằng nó thực sự là cùng một mối quan hệ. Cách chúng tôi làm điều này là với nghịch đảo bằng đúng.
Vì vậy, chúng ta hãy đi đến customer.hbm.xml ánh xạ tệp và đặt nghịch đảo bằng true như được hiển thị trong đoạn mã sau.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"
inverse = "true">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Khi lưu các lệnh, nó sẽ thiết lập khóa ngoại đó từ phía đơn hàng. Bây giờ hãy chạy lại ứng dụng này và mở hồ sơ NHibernate.
Nếu chúng ta nhìn vào cách chúng được chèn, chúng ta nhận được đoạn chèn trong khách hàng và chèn vào đơn đặt hàng, nhưng chúng tôi không có bản cập nhật trùng lặp của khóa ngoại vì nó đang được cập nhật khi đơn đặt hàng đang được lưu.
Bây giờ, bạn nên lưu ý rằng nếu bạn chỉ có một liên kết đơn hướng và đó là tập hợp đang duy trì mối quan hệ này, thì nếu bạn biến nghịch đảo bằng true, khóa ngoại đó sẽ không bao giờ được đặt và những mục đó sẽ không bao giờ có khóa ngoại được đặt trong cơ sở dữ liệu.
Nếu bạn nhìn vào mối quan hệ nhiều-một trong Order.hbm.xml và bạn tìm kiếm nghịch đảo, nó thực sự không có thuộc tính nghịch đảo.
Nó luôn được đặt từ mục con, nhưng nếu bạn có một bộ sưu tập nhiều đến nhiều, bạn có thể đặt nó từ một trong hai bên.
Trong chương này, chúng ta sẽ trình bày về cách hoạt động của các tính năng Tải và Nhận và cách chúng ta có thể sử dụng chúng. Đây là hai API rất giống nhau được cung cấp bởiISession để tải một đối tượng bằng khóa chính.
Get - nó sẽ trả về đối tượng hoặc giá trị null.
Load - nó sẽ trả về đối tượng hoặc nó sẽ ném một ObjectNotFoundException.
Bây giờ, tại sao chúng ta có hai API khác nhau này?
Tải
Đó là vì Tải có thể tối ưu hóa các chuyến đi vòng quanh cơ sở dữ liệu hiệu quả hơn nhiều.
Tải thực sự trả về một đối tượng proxy và không cần truy cập cơ sở dữ liệu ngay khi bạn thực hiện lệnh gọi Tải đó.
Khi bạn truy cập proxy đó, đối tượng không có trong cơ sở dữ liệu, nó có thể ném một ObjectNotFoundException vào thời điểm đó.
Được
Ngược lại, với Nhận vì những hạn chế của CLR hoặc Common Language Runtime và NHibernate phải đi đến cơ sở dữ liệu ngay lập tức, kiểm tra xem các đối tượng có ở đó không và trả về null, nếu nó không hiện diện.
Nó không có tùy chọn đối tượng để trì hoãn tìm nạp đó, vòng quay đó đến cơ sở dữ liệu sau đó vì nó không thể trả về một đối tượng proxy và đã hoán đổi đối tượng proxy đó cho một giá trị rỗng, khi người dùng thực sự truy cập vào nó.
Hãy xem xét một ví dụ đơn giản, trong đó bạn sẽ thấy chúng được sử dụng thực sự như thế nào và sự khác biệt giữa Get và Load. Chúng tôi sẽ tiếp tục với các lớp miền tương tựCustomers và Orders và tương tự các tệp ánh xạ tương tự từ chương trước.
Trong ví dụ này, đầu tiên chúng ta sẽ sử dụng Get như trong chương trình sau.
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 id1 = Guid.Parse("4e97c816-6bce-11e1-b095-6cf049ee52be");
var id2 = Guid.Parse("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE");
var customer1 = session.Get<Customer>(id1);
Console.WriteLine("Customer1 data");
Console.WriteLine(customer1);
var customer2 = session.Get<Customer>(id2);
Console.WriteLine("Customer2 data");
Console.WriteLine(customer2);
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 chúng tôi có hai GuidID của, cái đầu tiên là một ID tốt, đó là ID của một khách hàng mà chúng tôi biết có trong cơ sở dữ liệu. Trong khi ID thứ hai không có trong cơ sở dữ liệu. Cả hai ID này đều được chuyển dưới dạng tham số choGet() và sau đó kết quả được in trên bàn điều khiể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.
Customer1 data
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
Customer2 data
Press <ENTER> to exit...
Như bạn có thể thấy rằng dữ liệu Customer1 được in nhưng dữ liệu Customer2 trống, đó là vì bản ghi Customer2 không có sẵn trong cơ sở dữ liệu.
Khi bạn chạy lại ứng dụng của mình, chúng tôi có thể chèn một điểm ngắt trước câu lệnh cam kết và sau đó hãy xem xét cả hai khách hàng trong cửa sổ Xem.
Như bạn có thể thấy rằng dữ liệu Customer1 có sẵn, trong khi Customer2 là trống và loại là NHibernateDemo.Customer cho cả hai.
Bây giờ chúng ta hãy sử dụng phương thức Load thay vì Get trong cùng một ví dụ như trong đoạn mã sau.
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 id1 = Guid.Parse("4e97c816-6bce-11e1-b095-6cf049ee52be");
var id2 = Guid.Parse("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE");
var customer1 = session.Load<Customer>(id1);
Console.WriteLine("Customer1 data");
Console.WriteLine(customer1);
var customer2 = session.Load<Customer>(id2);
Console.WriteLine("Customer2 data");
Console.WriteLine(customer2);
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;
}
}
}
Bây giờ hãy chạy ví dụ này và bạn sẽ thấy rằng ngoại lệ sau đây được đưa ra như trong ảnh chụp màn hình.
Bây giờ nếu bạn nhìn vào cửa sổ Watch, bạn sẽ thấy loại là khách hàng proxy cho cả hai đối tượng. Và bạn cũng thấy dữ liệu tương tự cho Customer1 trên cửa sổ bảng điều khiển.
Customer1 data
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
Customer2 data
Trong chương này, chúng ta sẽ đề cập đến một API phổ biến khác mà mọi người sẽ sử dụng là nhà cung cấp NHibernate LINQ. Quyền truy cập của nó thông qua một phương thức mở rộng trên ISession và chữ ký là mộtQuery <T>. Có hai loại cú pháp khi sử dụng LINQ -
- Cú pháp chuỗi truy vấn
- Cú pháp hiểu truy vấn
Cú pháp chuỗi truy vấn
Bạn có thể truy cập bất kỳ bản ghi nào từ cơ sở dữ liệu bằng cách sử dụng cú pháp chuỗi phương pháp như được hiển thị trong chương trình sau.
var customer = session.Query<Customer>() .Where(c => c.FirstName == "Laverne")
Bạn có thể thấy rằng chúng ta có câu truy vấn và mệnh đề WHERE, bạn có thể có thêm mệnh đề WHERE và mệnh đề select tương tự.
Đây là một cú pháp chuỗi phương pháp tiêu chuẩn mà bạn có thể sử dụng trong LINQ bình thường.
LINQ to Objects hoặc LINQ to SQL, bất kỳ nhà cung cấp LINQ nào khác mà bạn có thể quen thuộc.
Hãy xem một ví dụ đơn giản, trong đó chúng ta sẽ truy xuất khách hàng có tên là Laverne. Bây giờ có khả năng chúng tôi có nhiều hơn một khách hàng có tên đầu tiên là Laverne, vì vậy chúng tôi sẽ chỉ truy xuất người đầu tiê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 customer = session.Query<Customer>()
.Where(c => c.FirstName == "Laverne").First();
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;
}
}
}
Bây giờ 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...
Cú pháp hiểu truy vấn
Ngoài ra còn có cú pháp hiểu truy vấn, trông giống như SQL hơn bằng cách sử dụng từ khóa from, where và select.
Vì vậy, chúng ta hãy xem xét cùng một ví dụ, nhưng lần này chúng ta sử dụng cú pháp hiểu LINQ, trông giống với SQL hơn như được hiển thị trong chương trình sau.
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 customer = (from c in session.Query<Customer>()
where c.FirstName == "Laverne" select c).First();
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;
}
}
}
Bây giờ hãy chạy lại ứng dụng này và 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...
Hãy xem xét một ví dụ khác, trong đó chúng tôi sẽ truy xuất tất cả những khách hàng đó, có FirstName bắt đầu bằng chữ H.
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.Query<Customer>() .Where(c =<
c.FirstName.StartsWith("H"));
foreach (var customer in customers.ToList()) {
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;
}
}
}
Tương tự, cú pháp hiểu truy vấn sẽ giống như chương trình sau.
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 = from c in session.Query<Customer>()
where c.FirstName.StartsWith("H") select c;
foreach (var customer in customers.ToList()) {
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;
}
}
}
Hãy chạy lại ứng dụng này và bạn sẽ thấy tất cả các khách hàng có tên bắt đầu bằng bảng chữ cái H.
Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 12/3/2010 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be
Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
Points: 56
HasGoldStatus: False
MemberSince: 10/20/2008 12:00:00 AM (Utc)
CreditRating: Terrible
AverageRating: 0
Orders:
Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be
Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
Points: 82
HasGoldStatus: False
MemberSince: 4/10/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
Press <ENTER> to exit...
Trong chương này, chúng tôi sẽ đề cập đến Ngôn ngữ Truy vấn Ngủ đông. HQL được chia sẻ trên cả Hibernate và NHibernate của Java.
Đây là cơ chế truy vấn lâu đời nhất cùng với Criteria.
Nó đã được triển khai rất sớm và nó là một truy vấn dựa trên chuỗi API.
Bạn truy cập nó thông qua ISession CreateQuery, và nó gần tương tự như SQL.
Nó sử dụng nhiều từ khóa giống nhau, nhưng có cú pháp đơn giản hóa.
Đây là một trong những ví dụ phổ biến nhất, nếu bạn đang tìm cách thực hiện truy vấn, bạn sẽ thường tìm thấy các ví dụ HQL.
Sau đây là một ví dụ đơn giản về HQL:
var customers = session.CreateQuery("select c from Customer c where c.FirstName = 'Laverne'");
Vì vậy, ở đây bạn có thể thấy rằng họ chọn C từ khách hàng, nó trông rất giống SQL. Đây là một chuỗi không rõ ràng theo như NHibernate có liên quan, vì vậy bạn không biết liệu đây có phải là HQL hợp lệ cho đến thời gian chạy hay không, đây là một trong những nhược điểm.
Một trong những điểm mạnh của nhà cung cấp LINQ là bạn có thể nhận hỗ trợ thời gian biên dịch.
Nhưng HQL, là một trong những cơ chế truy vấn linh hoạt nhất thường được sử dụng. Người ta nói rằng, nếu không có cách nào khác để làm điều đó thì có một cách để làm điều đó trong HQL.
Hãy xem một ví dụ đơn giản trong đó chúng tôi sẽ tạo lại các truy vấn LINQ của mình bằng cách sử dụng HQL. Bạn có thể truy cập vào HQL bằng cách gọisession.CreateQuery và chuyển dưới dạng một tham số bằng cách sử dụng một chuỗi HQL.
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.CreateQuery("select c from Customer c
where c.FirstName = 'Laverne'");
foreach (var customer in customers.List<Customer>()) {
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;
}
}
}
Chuỗi HQL này trông rất giống SQL, sự khác biệt chính là FirstName là tên thuộc tính chứ không phải tên cột.
Vì vậy, nếu có sự khác biệt giữa cả hai, bạn sử dụng tên thuộc tính. Tương tự, nó trông giống như một tên bảng, nhưng nó thực sự là tên của lớp mà chúng ta đang chọn.
Nếu bảng kết thúc sau được đặt tên là Khách hàng, chúng tôi sẽ vẫn sử dụng Khách hàng trong truy vấn HQL của mình.
Hãy chạy ứng dụng này và 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...
Hãy xem xét một ví dụ đơn giản khác, trong đó chúng tôi sẽ truy xuất tất cả những khách hàng có Tên đầu tiên bắt đầu bằng chữ H bằng cách sử dụng HQL.
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.CreateQuery("select c from Customer c
where c.FirstName like 'H%'");
foreach (var customer in customers.List<Customer>()) {
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;
}
}
}
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ó tên bắt đầu bằng H đều được trả về từ truy vấn này.
Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 12/3/2010 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be
Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
Points: 56
HasGoldStatus: False
MemberSince: 10/20/2008 12:00:00 AM (Utc)
CreditRating: Terrible
AverageRating: 0
Orders:
Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be
Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
Points: 82
HasGoldStatus: False
MemberSince: 4/10/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
Press <ENTER> to exit...
Chúng tôi có thể làm những việc phức tạp hơn như muốn tất cả các đơn đặt hàng mà khách hàng có số lượng đơn hàng lớn hơn 9. Sau đây là truy vấn HQL cho điều tương tự.
var customers = session.CreateQuery("select c from Customer c
where size(c.Orders) > 9");
foreach (var customer in customers.List<Customer>()) {
Console.WriteLine(customer);
}
Chúng tôi cũng cần chỉ ra rằng chúng tôi cần một kích thước ở đây hoặc số đếm hoặc chiều dài. Trong HQL, chúng tôi có tùy chọn sử dụng phương pháp kích thước đặc biệt như hình trên.
Cách khác để viết điều này, nếu bạn thích là c.Orders.size, và điều này có tác dụng chính xác.
var customers = session.CreateQuery("select c from Customer c
where c.Orders.size > 9");
foreach (var customer in customers.List<Customer>()) {
Console.WriteLine(customer);
}
Hãy chạy ứng dụng này.
Lindsay Towne (4ea3aef6-6bce-11e1-b0cb-6cf049ee52be)
Points: 50
HasGoldStatus: False
MemberSince: 4/13/2007 12:00:00 AM (Utc)
CreditRating: VeryGood
AverageRating: 0
Orders:
Order Id: 4ea3aef6-6bce-11e1-b0cc-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0cd-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0ce-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0cf-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d0-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d1-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d2-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d3-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d4-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d5-6cf049ee52be
Wyman Hammes (4ea61056-6bce-11e1-b0e2-6cf049ee52be)
Points: 32
HasGoldStatus: False
MemberSince: 2/5/2011 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 0
Orders:
Order Id: 4ea61056-6bce-11e1-b0e3-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e4-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e5-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e6-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e7-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e8-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e9-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0ea-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0eb-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0ec-6cf049ee52be
Press <ENTER> to exit...
Bạn có thể thấy rằng tất cả các khách hàng, những người có hơn 9 đơn đặt hàng được truy xuất từ cơ sở dữ liệu.
Trong chương này, chúng ta sẽ đề cập đến cơ chế truy vấn tiêu chí. CácNHibernate Query by Criteria API cho phép bạn tạo một truy vấn bằng cách thao tác các đối tượng tiêu chí trong thời gian chạy.
Cách tiếp cận này cho phép bạn chỉ định các ràng buộc động mà không cần thao tác chuỗi trực tiếp, nhưng nó không làm mất nhiều tính linh hoạt hoặc sức mạnh của HQL.
Mặt khác, các truy vấn được biểu thị dưới dạng tiêu chí thường khó đọc hơn các truy vấn được thể hiện trong HQL.
Cú pháp tiêu chí cổ điển là một API truy vấn dựa trên đối tượng như được hiển thị trong chương trình sau.
var customers = session.CreateCriteria<Customer>().Add(Restrictions.Like("FirstName", "H%"));
Như bạn có thể thấy, chúng tôi đang thực hiện một phiên tạo tiêu chí cho khách hàng và bây giờ chúng tôi đang thêm đối tượng hạn chế vào truy vấn đó.
Điều này hữu ích cho các trang truy vấn nơi người dùng có thể chọn các tùy chọn nhất định, nhưng không phải các tùy chọn khác.
Sẽ dễ dàng hơn để xây dựng truy vấn dưới dạng cây giống như cấu trúc truy vấn hơn là trong HQL hoặc LINQ, nơi bạn có thể sử dụng mệnh đề AND hoặc OR trong mệnh đề WHERE.
Sẽ dễ dàng hơn chỉ cần thêm các hạn chế bổ sung bằng cách sử dụng các đối tượng tiêu chí này.
Hãy xem xét một ví dụ đơn giản trong đó chúng ta sẽ tạo một truy vấn và có quyền truy cập vào API tiêu chí thông qua createCriteria và sau đó thêm một hạn chế là tên bắt đầu bằng H.
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.CreateCriteria<Customer>()
.Add(Restrictions.Like("FirstName", "H%"));
foreach (var customer in customers.List<Customer>()) {
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;
}
}
}
Khi đoạn mã trên được biên dịch và thực thi, bạn sẽ thấy kết quả sau.
Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 12/3/2010 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be
Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
Points: 56
HasGoldStatus: False
MemberSince: 10/20/2008 12:00:00 AM (Utc)
CreditRating: Terrible
AverageRating: 0
Orders:
Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be
Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
Points: 82
HasGoldStatus: False
MemberSince: 4/10/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
Press <ENTER> to exit…
Hãy xem xét một ví dụ đơn giản khác, trong đó chúng ta sẽ truy xuất khách hàng có tên bằng "Laverne"
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.CreateCriteria<Customer>()
.Add(Restrictions.Eq("FirstName", "Laverne")) .List<Customer>();
foreach (var customer in customers) {
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;
}
}
}
Hãy chạy lại ứng dụng này và 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...
Bây giờ, một trong những nhược điểm lớn của API tiêu chí là những chuỗi không rõ ràng này trong tên thuộc tính. Vì vậy, nếu tên đầu tiên được cấu trúc lại thành một cái gì đó khác, công cụ tái cấu trúc sẽ không nhất thiết phải chọn chuỗi mờ.
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 trê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 rất 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 lại đ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.
Trong chương này, chúng ta sẽ trình bày cách sử dụng các truy vấn SQL gốc trong NHibernate. Nếu bạn đã sử dụng SQL viết tay trong một số năm, bạn có thể lo ngại rằng ORM sẽ làm mất đi một số tính biểu cảm và tính linh hoạt mà bạn quen dùng.
Các phương tiện truy vấn mạnh mẽ của NHibernate cho phép bạn thực hiện hầu hết mọi thứ bạn làm trong SQL và trong một số trường hợp còn hơn thế nữa.
Đối với những trường hợp hiếm hoi mà bạn không thể làm cho các cơ sở truy vấn của NHibernate thực hiện chính xác những gì bạn muốn.
NHibernate cho phép bạn truy xuất các đối tượng bằng phương ngữ SQL gốc trong cơ sở dữ liệu của bạn.
Hãy xem một ví dụ đơn giản về các truy vấn SQL gốc trong NHibernate.
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;
using NHibernate;
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()) {
IQuery sqlQuery = session.CreateSQLQuery("SELECT * FROM
CUSTOMER").AddEntity(typeof(Customer));
var customers = sqlQuery.List<Customer>();
foreach (var customer in customers) {
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;
}
}
}
Ví dụ trên sử dụng CreateSQLQuery() để lấy lại danh sách các đối tượng và bạn cũng sẽ nhận thấy rằng loại thực thể gốc mà bạn muốn truy vấn trả về được chỉ định là Khách hàng.
Hãy chạy ứng dụng của bạn và bạn sẽ thấy rằng tất cả khách hàng được truy xuất từ cơ sở dữ liệu.
Emerson Prosacco (4ec2a0e0-6bce-11e1-b2cf-6cf049ee52be)
Points: 17
HasGoldStatus: False
MemberSince: 6/22/2007 12:00:00 AM (Utc)
CreditRating: Excellent
AverageRating: 0
Orders:
Order Id: 4ec2a0e0-6bce-11e1-b2d0-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d1-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d2-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d3-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d4-6cf049ee52be
Kaci Friesen (4ec2a0e0-6bce-11e1-b2d5-6cf049ee52be)
Points: 30
HasGoldStatus: True
MemberSince: 5/25/2007 12:00:00 AM (Utc)
CreditRating: VeryVeryGood
AverageRating: 0
Orders:
Order Id: 4ec2a0e0-6bce-11e1-b2d6-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d7-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d8-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d9-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2da-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2db-6cf049ee52be
Eveline Waters (4ec2a0e0-6bce-11e1-b2dc-6cf049ee52be)
Points: 58
HasGoldStatus: False
MemberSince: 10/29/2009 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 0
Orders:
Order Id: 4ec2a0e0-6bce-11e1-b2dd-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2de-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2df-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e0-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e2-6cf049ee52be
Molly Kuhn (4ec2a0e0-6bce-11e1-b2e3-6cf049ee52be)
Points: 73
HasGoldStatus: False
MemberSince: 12/16/2007 12:00:00 AM (Utc)
CreditRating: VeryGood
AverageRating: 0
Orders:
Order Id: 4ec2a0e0-6bce-11e1-b2e4-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e5-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e6-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e7-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e8-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e9-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2ea-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2eb-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2ec-6cf049ee52be
Đây là một cách khác để viết truy vấn SQL gốc như hình dưới đây.
IList<Customer> customers = session.CreateSQLQuery("SELECT * FROM CUSTOMER")
.AddScalar("Id", NHibernateUtil.Guid)
.AddScalar("FirstName", NHibernateUtil.String)
.AddScalar("LastName", NHibernateUtil.String) .List<Customer>();
Như bạn có thể thấy rằng truy vấn trên đã chỉ định chuỗi truy vấn SQL và các cột và kiểu trả về.
Điều này sẽ trả về một IList của mảng Đối tượng với các giá trị vô hướng cho mỗi cột trong bảng Khách hàng.
Chỉ ba cột này sẽ được trả về, ngay cả khi truy vấn đang sử dụng * và có thể trả về nhiều hơn ba cột được liệt kê.
Hãy xem xét một ví dụ đơn giản khác.
IList<Customer> customers = session.CreateSQLQuery("SELECT * FROM CUSTOMER WHERE
FirstName = 'Laverne'")
.AddEntity(typeof(Customer)) .List<Customer>();
foreach (var customer in customers) {
Console.WriteLine(customer);
}
Hãy chạy lại ứng dụng của bạn và 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...
Tương tự, bạn có thể chỉ định bất kỳ loại truy vấn SQL nào để lấy dữ liệu từ cơ sở dữ liệu.
Trong chương này, chúng tôi sẽ đề cập đến NHibernate thông thạo. Fluent NHibernate là một cách ánh xạ khác hoặc bạn có thể nói nó là một giải pháp thay thế cho các tệp ánh xạ XML chuẩn của NHibernate. Thay vì viết XML(.hbm.xml files)các tài liệu. Với sự trợ giúp của Fluent NHibernate, bạn có thể viết ánh xạ bằng mã C # được gõ mạnh.
Trong Fluent NHibernate, các ánh xạ được biên dịch cùng với phần còn lại của ứng dụng của bạn.
Bạn có thể dễ dàng thay đổi ánh xạ của mình giống như mã ứng dụng của bạn và trình biên dịch sẽ không thành công với bất kỳ lỗi chính tả nào.
Nó có một hệ thống cấu hình thông thường, nơi bạn có thể chỉ định các mẫu để ghi đè các quy ước đặt tên và nhiều thứ khác.
Bạn cũng có thể đặt cách mọi thứ nên được đặt tên một lần, sau đó Fluent NHibernate thực hiện phần còn lại.
Hãy xem một ví dụ đơn giản bằng cách tạo một dự án bảng điều khiển mới. Trong chương này, chúng ta sẽ sử dụng một cơ sở dữ liệu đơn giản, trong đó chúng ta có một bảng Khách hàng đơn giản như thể hiện trong hình sau.
Cài đặt Fluent NHibernate
Bước đầu tiên để khởi động Fluent NHibernate là cài đặt gói Fluent NHibernate. Vì vậy, hãy mởNuGet Package Manager Console và nhập lệnh sau.
PM> install-package FluentNHibernate
Sau khi cài đặt thành công, bạn sẽ thấy thông báo sau.
Hãy thêm một lớp mô hình đơn giản của Khách hàng và chương trình sau đây cho thấy việc triển khai lớp Khách hàng.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FluentNHibernateDemo {
class Customer {
public virtual int Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
}
Bây giờ chúng ta cần tạo Ánh xạ bằng NHibernate thông thạo, vì vậy hãy thêm một lớp nữa CustomerMaptrong dự án của bạn. Đây là phần triển khai của lớp CustomerMap.
using FluentNHibernate.Mapping;
using System;
using System.Collections.Generic;
using System.Linq; using System.Text;
using System.Threading.Tasks;
namespace FluentNHibernateDemo {
class CustomerMap : ClassMap<Customer> {
public CustomerMap() {
Id(x => x.Id);
Map(x => x.FirstName);
Map(x => x.LastName);
Table("Customer");
}
}
}
Hãy thêm một lớp khác NHibernateHelper trong đó chúng tôi sẽ thiết lập các cài đặt cấu hình khác nhau.
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Tool.hbm2ddl;
namespace FluentNHibernateDemo {
public class NHibernateHelper {
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory {
get {
if (_sessionFactory == null)
InitializeSessionFactory(); return _sessionFactory;
}
}
private static void InitializeSessionFactory() {
_sessionFactory = Fluently.Configure()
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
.Database(MsSqlConfiguration.MsSql2008 .ConnectionString(
@"Data Source + Initial Catalog + Integrated Security + Connect Timeout
+ Encrypt + TrustServerCertificate + ApplicationIntent +
MultiSubnetFailover") .ShowSql() )
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<Program>())
.ExposeConfiguration(cfg => new SchemaExport(cfg)
.Create(true, true))
.BuildSessionFactory();
}
public static ISession OpenSession() {
return SessionFactory.OpenSession();
}
}
}
Bây giờ chúng ta hãy chuyển sang Program.cs trong đó chúng ta sẽ bắt đầu một phiên và sau đó tạo một khách hàng mới và lưu khách hàng đó vào cơ sở dữ liệu như hình dưới đây.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FluentNHibernateDemo {
class Program {
static void Main(string[] args) {
using (var session = NHibernateHelper.OpenSession()) {
using (var transaction = session.BeginTransaction()) {
var customer = new Customer {
FirstName = "Allan",
LastName = "Bomer"
};
session.Save(customer);
transaction.Commit();
Console.WriteLine("Customer Created: " + customer.FirstName + "\t" +
customer.LastName);
}
Console.ReadKey();
}
}
}
}
Hãy chạy ứng dụng của bạn và bạn sẽ thấy kết quả sau.
if exists (select * from dbo.sysobjects where id = object_id(N'Customer') and
OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Customer
create table Customer (
Id INT IDENTITY NOT NULL,
FirstName NVARCHAR(255) null,
LastName NVARCHAR(255) null,
primary key (Id)
)
NHibernate: INSERT INTO Customer (FirstName, LastName) VALUES (@p0, @p1);
select SCOPE_IDENTITY();@p0 = 'Allan' [Type: String (4000)],
@p1 = 'Bomer' [Type: String (4000)]
Customer Created: Allan Bomer
Như bạn có thể thấy, khách hàng mới đã được tạo. Để xem hồ sơ khách hàng, chúng ta hãy vào cơ sở dữ liệu và xem Dữ liệu xem và bạn sẽ thấy rằng 1 Khách hàng được thêm vào.