zoukankan      html  css  js  c++  java
  • Nhibernate随手记(1)

       学习Nhibernate的萌芽

        今早有群里有人问Nhibernate的问题,没学过,刚好来了兴趣,无意很快在园子里下载到了一本Nhibernate3.0的电子书,内容非常不错,很快地看了扫了一下,再记个笔记,不过针对当前的最新版本文章的内容参考时候因稍作调整。一直觉得EF用起来蛮好用的,很多人喜欢EF,接触了好多初学EF Code First的同学,虽然有现成的工具在建好数据库后自动生成Code First 模式的代码文件,但自己建模都比较含糊,往往不清楚怎么去建立合适的Model,所以学习一下Nhibernate也是有好处的,我也可以了解下这个大名鼎鼎的hibernate移植版,因为这些都很直观,而且对于延迟加载也会有深入的理解。今天就开始我的Nhibernate入体验了此文适合想入门了解Nhibernate的童鞋看。电纸书(英文版)下载地址:点击这里

      建立我的第一个Nhibernate学习项目

     本项目包含元素套件

      1.Nhibernate_One_Lib 类库文件一枚

      2.Nhibernate_One_App 控制台营养程序一枚

      3.一个名为Schema解决方案文件夹,包含(nhibernate-configuration.xsd,nhibernate-mapping.xsd)

      4.官网下载的最新版本的Nhibernate3.3,本例不打算FluentNHibernate的无配置文件强类型的方式使用NHibernate,单纯体验配置的乐趣

      5.耐心一颗

      备注:套件3你可以完全不需要,如果你认为你习惯使用了Ctrl+C ,Ctrl+V不需要智能提示的话,完全可以不需要。

       1.首先我们看一下Nhibernate_One_Lib中所包含类之间的关系及内部元素的概况

         

     2.各个实体类文件的数据如下,同时我把我使用体会的一些细节说一下,希望理解错的地方大家可以指正一下:

      在Nhibernate中,每个实体类对应一个xml文件,其名称约定为:类名+.hbm.xml(hbm其实是Hibernate Mapping的缩写),在加载实体集的时候,NHibernate框架就会根据相应的类型搜索对应的xml进行关联,例如 名为Person的类,应该有一个对应的Person.hbm.xml文件进行元数据的描述。当然使用FluentNHibernate无需该配置文件。

    Entity<T>

    namespace Nhibernate_One_Lib
    {
        public abstract class Entity<T>
        {
            public virtual T Id { get; protected set;} 
    }
    }
    此处的protected修饰符其实没有对于Nhibernate没有任何意义,因为Nhibernate会忽略他的存在,只是为了保护数据不被人为修改

     Produnct类及其对应xml文件

    using System;
    
    namespace Nhibernate_One_Lib
    {
        public class Product : Entity<Guid>
        {
            public virtual string Name { get; set; }
    
            public virtual string Description { get; set; }
    
            public virtual decimal UnitPrice { get; set; }
        }
    }
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"  assembly="Nhibernate_One_Lib" namespace="Nhibernate_One_Lib">
     <class name="Product"  dynamic-update="true" optimistic-lock="dirty">
       <id name="Id">
         <generator class="guid.comb" />
       </id>
       <discriminator column="ProductType" />
       <natural-id mutable="true">
         <property name="Name" not-null="true" />
       </natural-id>
       <property name="Description" />
       <property name="UnitPrice" not-null="true" type="Currency" />
     </class>
    </hibernate-mapping>

    PS: 1.id ,natural-id,分别为托管标识和自然标识, Nhibernate极力推荐托管标志并为其存储格式制订一个枚举类型,这是在处理数据迁移是会很方便。

      2.dynamic-update="true" optimistic-lock="dirty" 

       这是用于多用户并发控制的设置项,关于乐观并发和悲观可以看一下园子里的文章介绍。下面是Dynamic update的优点描述。

      When optimistic-lock is set to dirty, dynamic-update must be true. Dynamic update simply means that the update statement only updates dirty properties, or properties with changed values, instead of explicitly setting all properties.

    Book类及其对应xml文件

    namespace Nhibernate_One_Lib
    {
        public class Book : Product
        {
            public virtual string ISBN { get; set; }
    
            public virtual string Author { get; set; }
        }
    }
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Nhibernate_One_Lib" namespace="Nhibernate_One_Lib">
      <subclass name="Book" extends="Product"  dynamic-update="true">
        <property name="ISBN"></property>
        <property name="Author"></property>
      </subclass>
    </hibernate-mapping>

      首先我们知道Book类继承自Product类,那么我们看到配置文件中的标签 subclass ,extends就不难理解了

    下面是Moive和AcotorRole的一对多的关系映射,需要看仔细一些

    using System.Collections.Generic;
    
    namespace Nhibernate_One_Lib
    {
        public class Movie : Product
        {
            public virtual string Director { get; set; }
    
            public virtual IList<ActorRole> Actors { get; set; }
        }
    }
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"  assembly="Nhibernate_One_Lib" namespace="Nhibernate_One_Lib">
      <subclass name="Movie" extends="Product" dynamic-update="true">
        <property name="Director"></property>
        <list name="Actors" cascade="all-delete-orphan">
          <key column="MoiveId"></key>
          <index column="ActorId"></index>
          <one-to-many class="ActorRole" />
        </list>
      </subclass>
    </hibernate-mapping>

    --------------------------------------------------------------------------------------------------------------------

    using System;
    
    namespace Nhibernate_One_Lib
    {
        public class ActorRole : Entity<Guid>
        {
            public virtual string Actor { get; set; }
    
            public virtual string Role { get; set; }
    
            public virtual Movie Movie { get; set; }
        }
    }
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Nhibernate_One_Lib" namespace="Nhibernate_One_Lib">
      <class name="ActorRole">
        <id name="Id">
          <generator class="guid.comb" />
        </id>
        <property name="Actor" not-null="true" />
        <property name="Role" not-null="true" />
      </class>
    </hibernate-mapping>

    从上面的配置我们可以看出在ActorRole 类中Movie是一个导航属性

     <list name="Actors" cascade="all-delete-orphan">
          <key column="MoiveId"></key>
          <index column="ActorId"></index>
          <one-to-many class="ActorRole" />
     </list>

    这段配置文件我们会发Actors并不是Moive表中的数据项,也是一个导航属性,cascade="all-delete-orphan"指定了可以进行级联删除操作。ActorId,MoiveId则是ActorRole表中的数据项,key 指定了两个表之间使用MovieId进行关联,one-to-many class="ActorRole"是一对多关系的体现。

    Nhibernate_One_App 应用部分

      在引入Nhibernate.dll文件后,我们开始编辑配置文件

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <configSections>
        <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate" />
      </configSections>
      <connectionStrings>
        <add name="db" connectionString="Server=.;Database=NHCookbook; Trusted_Connection=SSPI" />
      </connectionStrings>
      <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
        <session-factory>
          <property name="proxyfactory.factory_class">
            NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate
          </property>
          <property name="dialect">
            NHibernate.Dialect.MsSql2008Dialect,NHibernate
          </property>
          <property name="connection.connection_string_name">
            db
          </property>
          <property name="show_sql">true</property>
          <property name="adonet.batch_size">
            100
          </property>
          <mapping assembly="Nhibernate_One_Lib" />
        </session-factory>
      </hibernate-configuration>
    </configuration>

    这段配置文件非常简单,我在使用的时候需要注意两点:

    1.我们不再需要第三方的代理类库支援,如 NHibernate.ByteCode.Castle.dll等,Nhibernate3.3已经自己实现了该功能。

    <property name="proxyfactory.factory_class">
        NHibernate.Bytecode.DefaultProxyFactoryFactory,NHibernate
     </property>

    2.我们可以使用下面的属性运行时查看Nhibernate自动生成的SQL语句。

      <property name="show_sql">true</property>

    代码运行测试部分

    using System;
    using System.Collections.Generic;
    
    namespace Nhibernate_One_App
    {
        internal class Excuter
        {
            private Configuration nhConfig;
    
            private ISessionFactory sessionFactory;
    
            public IStatelessSession session { get; private set; }
    
            public Excuter()
            {
                nhConfig = new Configuration().Configure();
                sessionFactory = nhConfig.BuildSessionFactory();
                session = sessionFactory.OpenStatelessSession();
            }
    
            private static void Main(string[] args)
            {
                var e = new Excuter();
                InsertMovie(e.session);
                PrintMovies(e.session);
                UpdateMoviePrice(e.session);
                PrintMovies(e.session);
                Console.WriteLine("执行完成");
                Console.ReadKey();
            }
    
            private static void InsertMovie(IStatelessSession session)
            {
                using (var tx = session.BeginTransaction())
                {
                    for (int i = 0; i < 2; i++)
                        session.Insert(new Movie()
                        {
                            Name = "Movie " + i.ToString(),
                            Description = "A great movie!",
                            UnitPrice = 14.95M,
                            Director = "Johnny Smith"
                        });
                    tx.Commit();
                }
            }
    
            public static void PrintMovies(IStatelessSession session)
            {
                {
                    using (var tx = session.BeginTransaction())
                    {
                        var movies = GetMovies(session);
                        foreach (var movie in movies)
                        {
                            Console.WriteLine(string.Format("Movie.Name={0},Movie.UnitPrice={1}", movie.Name, movie.UnitPrice));
                        }
                        tx.Commit();
                    }
                }
            }
    
            private static void UpdateMoviePrice(IStatelessSession session)
            {
                var movies = GetMovies(session);
                foreach (var movie in movies)
                {
                    movie.UnitPrice = (decimal)new Random().Next(10, 26) - 0.05M;
                    session.Update(movie);
                }
            }
    
            private static IEnumerable<Movie> GetMovies(IStatelessSession session)
            {
                return session.CreateQuery("from Movie").List<Movie>();
            }
        }
    }

    运行效果:

    本文用到的数据表脚本(运行后应该生成如下效果):

     

    USE [NHCookbook]
     GO
     /****** Object:  Table [dbo].[Product]    Script Date: 07/13/2013 11:31:15 ******/
     SET ANSI_NULLS ON
     GO
     SET QUOTED_IDENTIFIER ON
     GO
     CREATE TABLE [dbo].[Product](
         [Id] [uniqueidentifier] NOT NULL,
         [Name] [nvarchar](50) NOT NULL,
         [ProductType] [nvarchar](50) NOT NULL,
         [Description] [nvarchar](50) NULL,
         [UnitPrice] [decimal](18, 0) NOT NULL,
         [Director] [nvarchar](50) NULL,
         [Author] [nvarchar](50) NULL,
         [ISBN] [nvarchar](50) NULL
     ) ON [PRIMARY]
     GO
     /****** Object:  Table [dbo].[ActorRole]    Script Date: 07/13/2013 03:31:15 ******/
     SET ANSI_NULLS ON
     GO
     SET QUOTED_IDENTIFIER ON
     GO
     CREATE TABLE [dbo].[ActorRole](
         [Id] [uniqueidentifier] NOT NULL,
         [Actor] [nvarchar](50) NOT NULL,
         [Role] [nvarchar](50) NOT NULL,
         [MovieId] [uniqueidentifier] NULL,
         [ActorId] [int] NULL
     ) ON [PRIMARY]
     GO
    
    SQL脚本
    建表脚本

       

    一件简单的测试算是完成了, 会用简单的CRUD功能,Nhibernate也是非常简单方便的,但是深入我估计还是要花N久时间,以后还要多做练习。

  • 相关阅读:
    Dubbo服务的搭建
    实现类似AOP的封装和配置
    Java中的代理--proxy
    Java中的类加载器--Class loader
    Dubbo框架的说明
    Java中的泛型--generic
    git回退单个文件
    shell重定向的顺序问题
    Shell基本正则表达式和扩展正则表达式
    cgroup & oom-killer 简介
  • 原文地址:https://www.cnblogs.com/rohelm/p/3187275.html
Copyright © 2011-2022 走看看