• NHibernate之(20):再探SchemaExport工具使用


    本节内容

    引入

    上篇我们初步探索了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 Q&A

    下次继续分享NHibernate!

  • 相关阅读:
    一行语句让你的浏览器变成记事本
    为啥只有IPv4和IPv6,没有IPv5呢?
    在线C++编译器
    怎么让Visual Studiot在遇到一个project编译错误时停止编译其它project
    C#的继承类中static constructor的调用问题
    C#中静态构造函数导致的一个deadlock
    一个C++的轻量级的logger实现
    一个免费轻量的Mathematica替代Mathics
    实时交通路况
    构建WAP邮件发送服务器
  • 原文地址:https://www.cnblogs.com/a282421083/p/13444798.html
Copyright © 2020-2023  润新知