NHibernate之(20):再探SchemaExport工具使用
本節內容
- 引入
- 例項分析
- 1.表及其約束
- 2.儲存過程、檢視
- 結語
返回文章列表
引入
上篇我們初步探索了SchemaExport工具使用,知道如何使用SchemaExport工具和SchemaUpdate工具利用NHibernate持久化類和對映檔案刪除、建立、更新資料庫架構,這篇具體分析如何為表字段增加一些約束?如何生成儲存過程?如何生成檢視?使用SchemaExport工具幫你搞定。
例項分析
1.表及其約束
眾所周知,SchemaExport工具根據對映檔案來生成資料庫架構,在對映檔案中通過Class對映可以很方便的生成資料庫表。但是這篇我們看看對映的條件,所以我重新定義兩個實體CategorySchema和ProductSchema,一對多關係。
Step1:兩個實體持久化類編寫程式碼如下:
public class CategorySchema { public virtual Guid Id { get; set; } public virtual string Name { get; set; } } public class ProductSchema { public virtual Guid Id { get; set; } public virtual string Name { get; set; } public virtual int UnitsOnStock { get; set; } public virtual CategorySchema CategorySchema { get; set; } }
Step2:為兩個實體對映,使用最簡方式,編寫程式碼如下:
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel"> <class name="DomainModel.Entities.CategorySchema,DomainModel"> <id name="Id"> <generator class="guid"/> </id> <property name="Name"/> </class> <class name="DomainModel.Entities.ProductSchema,DomainModel"> <id name="Id"> <generator class="guid"/> </id> <property name="Name"/> <many-to-one name="CategorySchema" class="DomainModel.Entities.CategorySchema,DomainModel"/> </class> </hibernate-mapping>
Step3:編寫測試用例用於生成資料庫架構:
[Test] public void ExecuteSchemaTest() { var export = new SchemaExport(_cfg); export.Execute(true, true, false, true); }
Step4:測試!NHibernate生成語句如下:
if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FK45BBFB51BC9515A6]') AND parent_object_id = OBJECT_ID('ProductSchema')) alter table ProductSchema drop constraint FK45BBFB51BC9515A6 if exists (select * from dbo.sysobjects where id = object_id(N'ProductSchema') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table ProductSchema if exists (select * from dbo.sysobjects where id = object_id(N'CategorySchema') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table CategorySchema create table ProductSchema ( Id UNIQUEIDENTIFIER not null, Name NVARCHAR(255) null, CategorySchema UNIQUEIDENTIFIER null, primary key (Id) ) create table CategorySchema ( Id UNIQUEIDENTIFIER not null, Name NVARCHAR(255) null, primary key (Id) ) alter table ProductSchema add constraint FK45BBFB51BC9515A6 foreign key (CategorySchema) references CategorySchema
仔細看看生成的語句,都按預設的值生成了表,Name列字串型別NVARCHAR(255),預設為null;外來鍵預設一數字字串等。
1.設定非空型別和長度
在對映檔案中為ProductSchema實體的Name屬性新增:not-null="true"表示非空型別,length="50":列長度設定為50,程式碼片段如下:
<property name="Name" not-null="true" length="50"/>
測試,生成語句如下:
create table ProductSchema ( Id UNIQUEIDENTIFIER not null, Name NVARCHAR(50) not null, CategorySchema UNIQUEIDENTIFIER null, primary key (Id) )
2.設定外來鍵Foreign Keys
在對映檔案設定外來鍵名稱,注意有的需要兩邊都要設定才生效,程式碼片段如下:
<many-to-one name="CategorySchema" class="DomainModel.Entities.CategorySchema,DomainModel" foreign-key="FK_Product_Category"/>
生成語句如下:
if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FK_Product_Category]') AND parent_object_id = OBJECT_ID('ProductSchema')) alter table ProductSchema drop constraint FK_Product_Category ... alter table ProductSchema add constraint FK_Product_Category foreign key (CategorySchema) references CategorySchema
3.設定Unique約束
我們要求Name欄位唯一,新增Unique約束,程式碼片段如下:
<property name="Name" not-null="true" length="50" unique="true"/>
生成語句如下:
create table ProductSchema ( Id UNIQUEIDENTIFIER not null, Name NVARCHAR(50) not null unique, CategorySchema UNIQUEIDENTIFIER null, primary key (Id) )
還有一種unique-key約束,同時為兩個屬性設定unique-key約束。我們為Customer持久化類的FirstName和LastName屬性新增Unique約束:
編寫對映,設定FirstName和LastName的Unique約束為UK_Person_Name:
<property name="FirstName" not-null="true" length="50" unique-key="UK_Customer_Name"/> <property name="LastName" not-null="true" length="50" unique-key="UK_Customer_Name"/>
生成語句如下:
create table Customer( CustomerId INT IDENTITY not null, FirstName NVARCHAR(50) not null, LastName NVARCHAR(50) not null, primary key (CustomerId), unique (FirstName, LastName) )
4.設定索引Index
<property name="Name" not-null="true" length="50" unique="true" index="IDX_Product_Name" />
生成語句如下:
create table ProductSchema (Id UNIQUEIDENTIFIER...) create table CategorySchema (Id UNIQUEIDENTIFIER...) create index IDX_Product_Name on ProductSchema (Name)
5.設定Check約束
我們為UnitsOnStock值設定大於等於0:
<property name="UnitsOnStock" not-null="true" > <column name="UnitsOnStock" check="UnitsOnStock >= 0"/> </property>
生成語句如下:
create table ProductSchema ( Id UNIQUEIDENTIFIER not null, Name NVARCHAR(50) not null unique, UnitsOnStock INT null check( UnitsOnStock >= 0) , CategorySchema UNIQUEIDENTIFIER null, primary key (Id) )
好了,還有很多設定大家自己探索啦!知道了這些我們在寫對映的時候就注意啦!我之前對映檔案屬性對映為什麼寫的比較全呢?就是這個原因,便於生成資料庫架構是自己約束的並不是預設的。
2.儲存過程、檢視
除了表,我們還有儲存過程和檢視。怎麼利用SchemaExport工具生成儲存過程和檢視呢?在對映檔案中提供了database-object元素用來建立和刪除資料庫物件。
<database-object> <create>建立儲存過程或檢視語句等資料庫物件</create> <drop>刪除儲存過程或檢視語句等資料庫物件</drop> </database-object>
1.儲存過程
還記得我們在NHibernate之旅(17):探索NHibernate中使用儲存過程(下)中建立的三個儲存過程了嗎?當時我們在資料庫中手寫建立的啊。現在完全可以不用那種古老的方法啦。我們在對映檔案中編寫database-object:在建立資料庫架構時建立名為entitySProcs的儲存過程,在刪除資料庫架構時刪除名為entitySProcs的儲存過程。現在使用SchemaExport工具不僅僅生成了表,還生成了儲存過程。還剩兩個儲存過程就留給大家去完成吧。
<database-object> <create> CREATE PROCEDURE entitySProcs AS SELECT CustomerId,Version,Firstname,Lastname FROM Customer </create> <drop> DROP PROCEDURE entitySProcs </drop> </database-object>
2.檢視
還記得我們在NHibernate之旅(14):探索NHibernate中使用檢視中建立了第一個檢視了嗎?那時我們也是在資料庫中手動建立的,現在我們可以自動建立了!開啟CustomerView.hbm.xml檔案,新增database-object:在建立資料庫架構時建立名為viewCustomer的檢視,在刪除資料庫架構時刪除名為viewCustomer的檢視。
<database-object> <create> CREATE VIEW [dbo].[viewCustomer] AS SELECT DISTINCT c.CustomerId, c.Firstname, c.Lastname, o.OrderId, o.OrderDate FROM dbo.Customer AS c INNER JOIN dbo.[Order] AS o ON c.CustomerId = o.OrderId INNER JOIN dbo.OrderProduct AS op ON o.OrderId = op.[Order] INNER JOIN dbo.Product AS p ON op.Product = p.ProductId GROUP BY c.CustomerId, c.Firstname, c.Lastname, o.OrderId, o.OrderDate </create> <drop>drop view dbo.viewCustomer</drop> </database-object>
測試生成資料庫架構,出現錯誤“資料庫中已存在名為'viewCustomer'的物件”。這是什麼原因呢?看看NHibernate生成語句:
create table viewCustomer ( CustomerId INT IDENTITY NOT NULL, Firstname NVARCHAR(255) null, Lastname NVARCHAR(255) null, OrderId INT null, OrderDate DATETIME null, primary key (CustomerId) )
觀察NHibernate生成SQL語句發現NHibernate利用Class對映自動生成了viewCustomer表,因為NHibernate見到Class對映就認為是表,它不知道這裡對映的是檢視,檢視和表在對映檔案中沒有什麼區別。我們修改一下這個對映檔案,在database-object元素上面再新增一個database-object用於刪除NHibernate生成的表。
<database-object> <create>drop table dbo.viewCustomer</create> <drop>drop table dbo.viewCustomer</drop> </database-object>
這個database-object的意思就是在建立資料庫架構時刪除NHibernate自動生成的表viewCustomer,在刪除資料庫架構時刪除表viewCustomer。為什麼刪除兩次呢?因為我們有可能只Drop,那麼NHibernate就執行database-object中的Drop。
這樣在CustomerView.hbm.xml檔案中就有兩個database-object了,總體的意思就是在建立資料庫架構時刪除NHibernate自動生成的表viewCustomer並建立名為viewCustomer的檢視,在刪除資料庫架構時刪除名為viewCustomer表和名為viewCustomer的檢視。
結語
好了,終於把SchemaExport工具研究透徹了,應該沒有說漏別的東西,就到這裡了。下面看看NHibernate物件去,什麼狀態啦,快取啦。
本系列連結:NHibernate之旅系列文章導航
下次繼續分享NHibernate!