zoukankan      html  css  js  c++  java
  • NHibernate简单使用介绍

    1、在数据库中新建表格,并插入记录,SQL如下:

    USE WFC_DB
    
    GO
    
    create table Students
    (
    Id int primary key IDENTITY(1,1) not null,
    Name varchar(255),
    Age int,
    Score int
    )
    
    GO
    
    insert into Students values('cheng', 10, 60)
    insert into Students values('liu', 11, 80)
    View Code

    注意:表的Id字段设为自增长,即 IDENTITY(1,1)

    2、新建类库项目,添加实体类与映射文件

    实体类 Student.cs:

        public class Student
        {
            public virtual int Id { get; set; }
    
            public virtual string Name { get; set; }
    
            public virtual int Age { get; set; }
    
            public virtual int Score { get; set; }
        }
    View Code

    注意:属性需为virtual,否则报错

    映射文件Student.hbm.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHbernateLib" namespace="NHbernateLib">
      <!--<class name="NHbernateLib.Student, NHbernateLib" table="Students">-->
      <class name="Student" table="Students">
        <id name="Id">
          <generator class="native"></generator>
        </id>
        <property name="Name"></property>
        <property name="Age"></property>
        <property name="Score"></property>
      </class>
    </hibernate-mapping>
    View Code

    注意:1、映射文件须以.hbm.xml作为后缀,这是NHibernate所要求的;文件的前缀没有要求,如可以命名为Students.hbm.xml,但最好以实体名为前缀

       2、映射文件设为嵌入的资源,方法为:右击该文件,点击属性->选择生成操作,设为嵌入的资源

       3、注意标签<hibernate-mapping>中需注明程序集与命名空间,如果不注明则需在标签<class> name属性中明确类名与程序集,如注释

       4、如果运行时报该映射文件编译错误,则说明文件内容有误,最有可能的地方是类所属的程序集未指明

    3、添加NHibernate程序集引用与主配置文件

    程序集可在NHibernate官网上下载已编译好的dll,也可下载源码自己编译成dll

    复制NHibernate.dll、NHibernate.xml到该项目文件夹中,并引用前者(后者为注释文件,智能提示)

    注意:在很多博客中,作者指出需引用NHibernate官网提供的所有dll,但本例为NHibernate最简单应用,只需引用NHibernate.dll即可

    配置文件hibernate.cfg.xml采用源码中配置模板,本来采用SQL Server 2008,配置内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
      <session-factory>
        <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
        <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
        <!-- 以下两项可在配置文件中指明,也可在代码中动态指定 -->
        <!--<property name="connection.connection_string">server=yqzhu-peter;database=WFC_DB;uid=sa;pwd=ABcd1234;Connect Timeout=100</property>-->
        <!--<mapping assembly="NHibernateLib"/>-->
      </session-factory>
    </hibernate-configuration>
    View Code

    注意:1、主配置文件文件名hibernate.cfg.xml固定,不可更改

       2、文件属性设为始终复制,方法为:右击该文件,点击属性->选择复制到输出目录,设为始终复制,这样主配置文件位置可随意放置

    4、添加数据库操作接口类,如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using NHibernate;
    using NHibernate.Cfg;
    
    namespace NHbernateLib
    {
        public interface IStudentDao
        {
            object Save(Student entity);
    
            void Update(Student entity);
    
            void Delete(Student entity);
    
            Student Get(object id);
    
            Student Load(object id);
    
            void SaveOrUpdate(Student entity);
        }
    
        public class StudentDao : IStudentDao
        {
            private ISessionFactory sessionFactory;
    
            public StudentDao()
            {
                var configuration = new Configuration();
                configuration.Configure();
                configuration.SetProperty("connection.connection_string", "server=yqzhu-peter;database=WFC_DB;uid=sa;pwd=ABcd1234;Connect Timeout=100");
                configuration.AddAssembly(typeof(Student).Assembly);
                sessionFactory = configuration.BuildSessionFactory();
            }
    
            public object Save(Student entity)
            { 
                using(ISession session = sessionFactory.OpenSession())
                {
                    var id = session.Save(entity);
                    session.Flush();
                    return id;
                }
            }
    
            public void Update(Student entity)
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    session.Update(entity);
                    session.Flush();
                }
            }
    
            public void Delete(Student entity)
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    session.Delete(entity);
                    session.Flush();
                }
            }
    
            public Student Get(object id)
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    return session.Get<Student>(id);
                }
            }
    
            public Student Load(object id)
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    return session.Load<Student>(id);
                }
            }
    
            public void SaveOrUpdate(Student entity)
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    session.SaveOrUpdate(entity);
                    session.Flush();
                }
            }
        }
    }
    View Code

    5、在解决方案中添加控制台项目,在该项目中引用类库, program.cs如下:

            static void Main(string[] args)
            {
                IStudentDao studentDao = new StudentDao();
                Student student = new Student() { Id = 100, Age = 10, Name = "yang", Score = 90 };
    
                //var obj = studentDao.Save(student);
                //Console.WriteLine(obj.ToString());
    
                Student student2 = studentDao.Get(2);
                Console.WriteLine(student2.Score);
                student2.Score = 50;
                studentDao.SaveOrUpdate(student2);
                student2 = studentDao.Get(2);
                Console.WriteLine(student2.Score);
    
                //Student student2 = studentDao.Get(1);
                //Console.WriteLine(student2.Score);
                //studentDao.Delete(student2);
    
                Console.ReadKey();
            }
    View Code

    运行该项目,即可进行测试

    源码:NHbernateDemo.rar

    (本例包含NUnit测试代码,版本为NUnit 2.6.4, 可到官网下载安装包,其中load方法测试有问题,原因为load为延迟加载,对数据的访问必须有session存在)

    作为本博客的补充,可参考NHibernate使用之详细图解

    NHibernate使用注意事项:

    1、Get与Load的区别是:前者立即加载,后者延迟加载(默认情况下)

    2、当数据表关系存在(如多对一),使用Get获取对其他表的引用是延迟加载的

    3、NHibernate延迟加载须有Session存在,且配置为Lazy=true(默认),超过session访问延迟加载项时将会出错

    一个封装好的NHibernate实例NHibernateDemo2.rar

    表关系详解:

    一对一:

    1、数据库中建立数据表

    create table T_Student
    (
    StudentID int IDENTITY(1,1),
    Name varchar(25)    
    )
    
    create table T_Family
    (
    FamilyID int,
    Adress varchar(25)    
    )
    View Code

    注意:在配置文件Student.hbm.xml中,虽然配置T_Family的外键,但数据库中没有必要添加该限制

    2、添加类及相应配置配置

        public class Student
        {
            public virtual int ID { get; set; }
    
            public virtual string Name { get; set; }
        }
    
        public class Family
        {
            public virtual int ID { get; set; }
    
            public virtual string Adress { get; set; }
    
            public virtual Student Student { get; set; }
        }
    View Code
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHbernateLib" namespace="NHbernateLib">
      <class name="Student" table="T_Student">
        <id name="ID" column="StudentID">
          <generator class="native"/>
        </id>
        <property name="Name"/>
      </class>
      <class name="Family" table="T_Family">
        <id name="ID" column="FamilyID">
          <generator class="foreign">
            <param name="property">Student</param>
          </generator>
        </id>
        <property name="Adress"/>
        <one-to-one name="Student" constrained="true"/>
      </class>
    </hibernate-mapping>
    View Code

    需要注意的是:Family类中Student属性没有必要与类同名,如为Pupile,此时配置中<generator>中的参数应为Pupile,即与属性名相同(而非类型名)

    3、NUnit测试

        [TestFixture]
        public class StudentTest
        {
            private ISessionFactory sessionFactory;
    
            [TestFixtureSetUp]
            public void Init()
            {
                var configuration = new Configuration();
                configuration.Configure();
                configuration.SetProperty("connection.connection_string", "server=yqzhu-peter;database=WFC_DB;uid=sa;pwd=ABcd1234;Connect Timeout=100");
                configuration.AddAssembly(typeof(Student).Assembly);
                sessionFactory = configuration.BuildSessionFactory();
            }
    
            [Test]
            public void OneToOneAddTest()
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    using (ITransaction tran = session.BeginTransaction())
                    {
                        Student student = new Student() { Name = "liu" };
                        Family family = new Family() { Adress = "xiamen", Student = student};
                        session.SaveOrUpdate(family);
                        tran.Commit();
                    }
                }
            }
    
            [Test]
            public void OneToOneGetTest()
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    using (ITransaction tran = session.BeginTransaction())
                    {
                        Family family = session.Get<Family>(4);
                        Console.WriteLine(family.Adress) ;
                        Console.WriteLine(family.Student.Name);
                        tran.Commit();
                    }
                }
            }
        }
    View Code

    源码NHbernateDemo3.rar

    源码中包含双向引用的实例ChildTest,对应SQL

    create table T_Child
    (
    ChildID int IDENTITY(1,1),
    Name varchar(25)    
    )
    
    create table T_Mom
    (
    MomID int,
    Name varchar(25)    
    )
    View Code

    关于一对一关系需注意的事项:

    1、<one-to-one>默认的cascade为all,因此在默认情况下可将临时态(Transient)的实例持久化到数据库中

    2、在双向一对一关系中,从ID设为数据库自动生成的类的方向保存数据时(实例中的Child),必须设置该类所引用的类引用自身(即循环引用),否则将无法同时保存所引用的类,但从另一方向(实例中的Mom)则不存在该问题,但良好的实践是两种情况都设为循环引用

    一对多:

    1、数据库中建立数据表

    create table T_Student
    (
    StudentID int IDENTITY(1,1),
    Name varchar(25),
    FamilyID int    
    )
    
    create table T_Family
    (
    FamilyID int IDENTITY(1,1),
    Adress varchar(25)    
    )
    View Code

    注意:配置中Id生成方式设为native,在数据库中创建数据表时需要将Id设为自增长

    2、添加类及相应配置配置

        public class Student
        {
            public virtual int ID { get; set; }
    
            public virtual string Name { get; set; }
        }
    
        public class Family
        {
            public virtual int ID { get; set; }
    
            public virtual string Adress { get; set; }
    
            public virtual IList<Student> Students { get; set; }
        }
    View Code
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHbernateLib" namespace="NHbernateLib">
      <class name="Student" table="T_Student">
        <id name="ID" column="StudentID">
          <generator class="native"/>
        </id>
        <property name="Name"/>
      </class>
      <class name="Family" table="T_Family">
        <id name="ID" column="FamilyID">
          <generator class="native"/>
        </id>
        <property name="Adress"/>
        <bag name="Students" cascade="all">
          <key column="FamilyID"/>
          <one-to-many class="Student" />
        </bag>
      </class>
    </hibernate-mapping>
    View Code

    需要注意的是:key中column值为表T_Student中的字段,如果该字段值为Family,此时要将column值设为Family

    3、NUnit测试

        [TestFixture]
        public class StudentTest
        {
            private ISessionFactory sessionFactory;
    
            [TestFixtureSetUp]
            public void Init()
            {
                var configuration = new Configuration();
                configuration.Configure();
                configuration.SetProperty("connection.connection_string", "server=yqzhu-peter;database=WFC_DB;uid=sa;pwd=ABcd1234;Connect Timeout=100");
                configuration.AddAssembly(typeof(Student).Assembly);
                sessionFactory = configuration.BuildSessionFactory();
            }
    
            [Test]
            public void OneToManyAddTest()
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    using (ITransaction tran = session.BeginTransaction())
                    {
                        Student student1 = new Student() { Name = "liu" };
                        Student student2 = new Student() { Name = "cheng" };
                        Family family = new Family() { Adress = "xiamen" };
                        family.Students = new List<Student>() { student1, student2 };
                        //session.SaveOrUpdate(student1);
                        //session.SaveOrUpdate(student2);
                        session.SaveOrUpdate(family);
                        tran.Commit();
                    }
                }
            }
    
            [Test]
            public void OneToManyGetTest()
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    using (ITransaction tran = session.BeginTransaction())
                    {
                        Family family = session.Get<Family>(8);
                        Console.WriteLine(family.Adress);
                        Console.WriteLine(family.Students.Count);
                        tran.Commit();
                    }
                }
            }
        }
    View Code

    源码NHbernateDemo4.rar

     源码中包含了多对一(ChildTest),一对多与多对一双向关系(PupilTest)的实例

     ChildTest对应QSL:

    create table T_Child
    (
    ChildID int IDENTITY(1,1),
    Name varchar(25),
    MomID int    
    )
    
    create table T_Mom
    (
    MomID int IDENTITY(1,1),
    Name varchar(25)    
    )
    View Code

    PupilTest对应QSL:

    create table T_Pupil
    (
    PupilID int IDENTITY(1,1),
    Name varchar(25),
    ClassID int    
    )
    
    create table T_Class
    (
    ClassID int IDENTITY(1,1),
    Name varchar(25)    
    )
    View Code

    关于一对多,多对一关系需注意的事项:

    1、<bag>与<many-to-one>默认的cascade为none,因此需显式指定为all,方可保存临时态(Transient)实例

    2、这两种关系不存在一对一中需要循环引用的问题

    多对多:

    1、数据库中建立数据表

    create table T_User
    (
    UserID int IDENTITY(1,1),
    Name varchar(25)    
    )
    
    create table T_User_Role
    (
    RoleID int,
    UserID int
    )
    
    create table T_User_Role
    (
    RoleId int,
    UserId int
    )
    View Code

    2、添加类及相应配置配置

        public class Role
        {
            public virtual int ID { get; set; }
    
            public virtual string Name { get; set; }
    
            public virtual IList<User> Users { get; set; }
        }
    
        public class User
        {
            public virtual int ID { get; set; }
    
            public virtual string Name { get; set; }
    
            public virtual IList<Role> Roles { get; set; }
        }
    View Code
    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHbernateLib" namespace="NHbernateLib">
      <class name="Role" table="T_Role">
        <id name="ID" column="RoleID">
          <generator class="native"/>
        </id>
    
        <property name="Name" />
    
        <bag name="Users" table="T_User_Role" cascade="all">
          <key column="RoleId"/>
          <many-to-many class="User" column="UserId"/>
        </bag>
        
      </class>
    
      <class name="User" table="T_User" >
        <id name="ID" column="UserID">
          <generator class="native"/>
        </id>
    
        <property name="Name" />
    
        <bag name="Roles" table="T_User_Role" cascade="all">
          <key column="UserId"/>
          <many-to-many class="Role" column="RoleId"/>
        </bag>
    
      </class>
    </hibernate-mapping>
    View Code

    需要注意的是:key与<many-to-many>中column值为表T_User_Role中的字段,如果该字段值为user, role,此时要将column值分别设为user, role

    3、NUnit测试

        public class RoleTest
        {
            private ISessionFactory sessionFactory;
    
            [TestFixtureSetUp]
            public void Init()
            {
                var configuration = new Configuration();
                configuration.Configure();
                configuration.SetProperty("connection.connection_string", "server=yqzhu-peter;database=WFC_DB;uid=sa;pwd=ABcd1234;Connect Timeout=100");
                configuration.AddAssembly(typeof(Role).Assembly);
                sessionFactory = configuration.BuildSessionFactory();
            }
    
            [Test]
            public void ManyToManySaveTest()
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    using (ITransaction tran = session.BeginTransaction())
                    {
                        Role role1 = new Role() { Name = "Administer" };
                        Role role2 = new Role() { Name = "User" };
                        Role role3 = new Role() { Name = "Visitor" };
                        User user = new User() { Name = "cheng" };
                        user.Roles = new List<Role>() { role1, role2 };
                        //session.SaveOrUpdate(role1);
                        //session.SaveOrUpdate(role2);
                        //session.SaveOrUpdate(role3);
                        session.SaveOrUpdate(user);
                        tran.Commit();
                    }
                }
            }
    
            [Test]
            public void ManyToManyGetTest()
            {
                using (ISession session = sessionFactory.OpenSession())
                {
                    using (ITransaction tran = session.BeginTransaction())
                    {
                        Role role = session.Get<Role>(8);
                        Console.WriteLine(role.Name);
                        Console.WriteLine(role.Users.Count);
                        tran.Commit();
                    }
                }
            }
        }
    View Code

    源码NHbernateDemo5.rar

    关于多对多,注意<bag>默认的cascade为none,因此需显式指定为all,方可保存临时态(Transient)实例

    关于NHIbernate详细介绍可参考刘冬的博客

  • 相关阅读:
    12月14日总结观影数据集之大数据分析who
    12月09日总结python对json 数据转换
    12月12日总结观影数据集之大数据分析when
    阅读笔记
    12月11日总结观影数据集之大数据分析what
    12月13日总结where
    12月15日总结观影数据集之大数据分析how
    12月10日总结python数据备份
    12月16日观影大数据分析 how much
    可能的加分项
  • 原文地址:https://www.cnblogs.com/MattCheng/p/4619432.html
Copyright © 2011-2022 走看看