本節內容
引入
實例分析
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
3.設置Unique約束
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
我們要求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(
4.設置索引Index
CustomerId INT IDENTITY not null,
FirstName NVARCHAR(50) not null,
LastName NVARCHAR(50) not null,
primary key (CustomerId),
unique (FirstName, LastName)
)<property name="Name" not-null="true" length="50"
unique="true" index="IDX_Product_Name" />
生成語句如下:
create table ProductSchema (Id UNIQUEIDENTIFIER...)
5.設置Check約束
create table CategorySchema (Id UNIQUEIDENTIFIER...)
create index IDX_Product_Name on ProductSchema (Name)
我們為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>
1.存儲過程
<create>創建存儲過程或視圖語句等數據庫對象</create>
<drop>刪除存儲過程或視圖語句等數據庫對象</drop>
</database-object>
還記得我們在NHibernate之旅(17):探索NHibernate中使用存儲過程(下)中創建的三個存儲過程了嗎?當時我們在數據庫中手寫創建的啊。現在完全可以不用那種古老的方法啦。我們在映射文件中編寫database-object:在創建數據庫架構時創建名為entitySProcs的存儲過程,在刪除數據庫架構時刪除名為entitySProcs的存儲過程。現在使用SchemaExport工具不僅僅生成了表,還生成了存儲過程。還剩兩個存儲過程就留給大家去完成吧。
<database-object>
2.視圖
<create>
CREATE PROCEDURE entitySProcs
AS
SELECT CustomerId,Version,Firstname,Lastname FROM Customer
</create>
<drop>
DROP PROCEDURE entitySProcs
</drop>
</database-object>
還記得我們在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對象去,什麼狀態啦,緩存啦。
出處:http://lyj.cnblogs.com