NHbiernate映射工具连接MySQL的基本配置及使用

NHbiernate介绍

NHibernate是一个面向.NET环境的对象/关系数据库映射工具。对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。

基本配置

NHbiernate基本配置

  1. 新建一个项目取名为NHibernateTest,项目中添加MySQL.Data和NHbiernate的引用。
  1. 在项目下创建一个XML文件,必须叫hibernate.cfg.xml ,因为NHbiernate会在根目录下找这个名字的xml文件,如果不叫这个名字会报错。并把该文件的属性设置 为始终复制。
    在官网上找到以下代码,打开这个xml文件进行编辑:
    官网是连的SQL Server, 这里连得是MySQL, 所以更改一下, 这里主要设置了第二行的MySQL5Dialect,和第三行的MySQLDataDriver,第四行的Server=localhost;Database=sikidb;User ID=root;Password=zzzzz; 注意一定把要访问的数据库名和用户名密码写正确。
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
    <property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
    <property name="connection.connection_string">Server=localhost;Database=sikidb;User ID=root;Password=zzzzz;</property>
    <property name="show_sql">true</property>
  </session-factory>
</hibernate-configuration>
  1. 再新建一个Model文件夹,在这个文件夹下新建一个User类,把数据库中对应的表中的每行的数据名创建成每个变量,如下:
    user表里有四列数据就写四个对应的变量,一定要是virtual 类型的,这是NHbiernate要求写法。

  1. 在项目下在创建一个Mappings文件夹,在这个文件夹下创建一个User.hbm.xml命名的xml文件,并把它的属性里的生成操作改为嵌入的资源。打开编辑一下代码:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="NHibernateTest"
                   namespace="NHibernateTest.Model">
  <class name="User" table ="users">
    <id name="Id" column="id" type="Int32">
      <generator class="native"></generator>
    </id>
    <property name="Username" column="username" type="String"></property>
    <property name="Password" column="password" type="String"></property>
    <property name="Registerdate" column="registerdate" type="Date"></property>
  </class>
</hibernate-mapping>

这里主要是配置NHbiernate的映射,数据库里的表的每行数据名和类型都要正确填写,主键要多设置一行自动增长 ,以下是数据库每行数据名和类型:

到这里就基本配置完成了,下图是各个文件目录:

测试

在主函数里写下以下代码,测试一下NHbiernate连接MySql增加数据的功能

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernate;
using NHibernate.Cfg;
using NHibernateTest.Model;//引入自己创建的目录下的类
namespace NHibernateTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var config = new Configuration();
            config.Configure();//开始解析文件hibernate.cfg.xml
            config.AddAssembly("NHibernateTest");
            ISessionFactory sessionFactory = null;
            ISession session = null;
            try
            {
                sessionFactory = config.BuildSessionFactory();
                session = sessionFactory.OpenSession();//打开一个跟数据库的会话
                User user = new User() { Username = "vvvv", Password = "121212" };
                session.Save(user);//NHibernate里面的增加数据的方式,Session实例由ISessionFactory构建
                //Session是Hibernate持久化操作的基础,提供了众多持久化方法,如save、update、delete等。通过这些方法,透明地完成对象的增加、删除、修改、查找等操作。
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            finally
            {
                if (session != null)
                {
                    session.Close();
                }
                if (sessionFactory != null)
                {
                    sessionFactory.Close();
                }
            }
            Console.ReadKey();
        }
    }
}

运行前后对比

这张图是以上代码没有运行前数据库中的user表里的数据:

这个是运行后,数据库的数据,可以看到在最后增加了一条Username = “vvvv”, Password = “121212”,的数据:

注意

删除的不能直接使用session.Delete(user) ,百度了一下这段话: delete()方法用于从数据库中删除与Java对象对应的记录。如果传入的参数是持久化对象,Session就计划执行一个delete语句。如果传入的参数是游离对象,先使游离对象被Session关联,使它变为持久化对象,然后计划执行一个delete语句。值得注意的是,Session只有在清理缓存的时候的才执行delete语句。此外,只有当调用Session的close()方法时,才会从Session的缓存中删除该对象。需要先清理缓存,才可以执行删除:

try
{
    sessionFactory = config.BuildSessionFactory();
    session = sessionFactory.OpenSession();//打开一个跟数据库的会话
    ITransaction transaction = session.BeginTransaction();//开启事务。删除的话需要写上这一句话,在提交事务时才可以删掉,不写的话,控制台不报任何错误,但是也没有删掉数据
    User user = new User() {Id=18};
    session.Delete(user);
    transaction.Commit();// 提交事务,清理缓存,执行delete语句 
}
catch (Exception e)
{
    Console.WriteLine(e);
}
finally
{
    if (session != null)
    {
        session.Close();
    }
    if (sessionFactory != null)
    {
        sessionFactory.Close();
    }
}

siki视频中的利用NHbiernate事务机制来增加和删除:
关于关闭这些需要注意,先开启的后关闭,后开启的先关闭

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernate;
using NHibernate.Cfg;
using NHibernateTest.Model;//引入自己创建的目录下的类
namespace NHibernateTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var config = new Configuration();
            config.Configure();//开始解析文件hibernate.cfg.xml
            config.AddAssembly("NHibernateTest");
            ISessionFactory sessionFactory = null;
            ISession session = null;
            ITransaction transaction = null;
            try
            {
                sessionFactory = config.BuildSessionFactory();
                session = sessionFactory.OpenSession();//打开一个跟数据库的会话
                transaction = session.BeginTransaction();//注册事务
                User user = new User() { Username = "qwrrtu", Password = "131313" };
                User user1 = new User() { Id = 26 }; //删除操作,只给主键值就可以了
                session.Save(user);
                session.Delete(user1);
                transaction.Commit();//开启事务
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            finally //关于关闭这些需要注意,先开启的后关闭,后开启的先关闭
            {
                if (transaction != null)
                {
                    transaction.Dispose();
                }
                if (session != null)
                {
                    session.Close();
                }
                if (sessionFactory != null)
                {
                    sessionFactory.Close();
                }
            }
            Console.ReadKey();
        }
    }
}

封装

以上就是基本写法,但是由于执行增删改查时频繁的使用ISessionFactory来创建会话,所以封装一个类来创建会话,需要执行这些操作的时候直接引用这个管理类里面的方法就可以了:

1.

首先添加一个类,命名为NHibernateHelper ,添加以下代码:(在这里进行创建会话,不用每次使用时都新开一个会话)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
namespace NHibernateTest
{
    public class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;
        public static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    var config = new Configuration();
                    config.Configure();//开始解析文件hibernate.cfg.xml
                    config.AddAssembly("NHibernateTest");
                    _sessionFactory = config.BuildSessionFactory();
                }
                return _sessionFactory;
            }
        }
        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }
}

2.

在目录下创建一个叫Manager的文件夹,添加一个接口,命名为IUsermanager ,写入以下代码:
(这里定义了一些增删改查的方法,和通过ID查询用户数据的复杂查询方法,和验证用户名密码是否存在的方法)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernateTest.Model;
namespace NHibernateTest.Manager
{
    public interface IUserManager
    {
        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="user">User表中的数据</param>
        void Add(User user);
        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="user">User表中的数据</param>
        void Updata(User user);
        /// <summary>
        /// 删除某条指定数据
        /// </summary>
        /// <param name="user">User表中的数据</param>
        void Delete(User user);
        /// <summary>
        /// 通过用户ID查询数据
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        User GetUserById(int id);
        /// <summary>
        /// 通过用户名查询数据
        /// </summary>
        /// <param name="username"></param>
        /// <returns></returns>
        User GetUserByUsername(string username);
        /// <summary>
        /// 查询表中所有数据
        /// </summary>
        /// <returns></returns>
        ICollection<User> GetAllUsers();
        /// <summary>
        /// 验证用户名密码是否存在
        /// </summary>
        /// <param name="username">用户名</param>
        /// <param name="password">密码</param>
        /// <returns></returns>
        bool VerifyUser(string username, string password);
    }
}

3.

在这个文件夹下,再添加一个叫Usermanager的类,继承自IUsermanager这个接口,写入以下代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernateTest.Model;
using NHibernate;
using NHibernate.Criterion;
namespace NHibernateTest.Manager
{
    public class UserManager : IUserManager
    {
        public void Add(User user)
        {
            //第一种写法:
            //ISession session = NHibernateHelper.OpenSession();
            //session.Save(user);
            //session.Close();
            //第二种写法:
            //Using语句意思是在大括号里的代码执行完以后释放小括号里面的资源
            //使用using,定义范围,在该范围结束时回收资源。功能等同于try{ }Finally{ }。
            using (ISession session = NHibernateHelper.OpenSession()) //下面的代码执行完会在这路关闭session
            {
                using(ITransaction transaction = session.BeginTransaction())
                {
                    session.Save(user);
                          transaction.Commit();//开启事务,执行完以后才会在using里关闭
                }
               
            }
        }
        public void Delete(User user)
        {
            using (ISession session = NHibernateHelper.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    session.Delete(user);
                          transaction.Commit();
                }
            }
        }
        public void Updata(User user)
        {
            using (ISession session = NHibernateHelper.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    session.Update(user);
                          transaction.Commit();
                }
            }
        }
        public User GetUserById(int id)
        {
            using (ISession session = NHibernateHelper.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    User user = session.Get<User>(id);
                          transaction.Commit();
                    return user;//获取到user里的id后返回
                }
            }
        }
       
        public ICollection<User> GetAllUsers()
        {
            using (ISession session = NHibernateHelper.OpenSession())
            {
                IList<User> users = session.CreateCriteria(typeof(User)).List<User>();//返回User里的多个值,就不能用UniqueResult了
                return users;
            }
        }
        public User GetUserByUsername(string username)
        {
            using(ISession session = NHibernateHelper.OpenSession())
            {
                //第一种写法:
                //CreateCriteria方法是指定要查询哪个表格,接收类型参数,把user这个类型传给他就可以了
                //ICriteria criteria = session.CreateCriteria(typeof(User));
                //criteria.Add(Restrictions.Eq("Username", username));//Restrictions.Eq 等于的意思
                //User user = criteria.UniqueResult<User>();//UniqueResult 这里只返回一个值
                //第一种的简写方式:
                User user = session.CreateCriteria(typeof(User)).Add(Restrictions.Eq("Username", username)).UniqueResult<User>();
                return user;
            }
        }
        public bool VerifyUser(string username, string password)
        {
            using (ISession session = NHibernateHelper.OpenSession())
            {
                //和通过用户名查询数据类似,这里多加一个密码条件就可以了
                User user = session.CreateCriteria(typeof(User)) .Add(Restrictions.Eq("Username", username)) .Add(Restrictions.Eq("Password", password)) .UniqueResult<User>();
                if (user == null)
                {
                    return false;
                }
                return true;
            }
        }
    }
}

4.

最后在主函数里进行测试这些封装的方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernate;
using NHibernate.Cfg;
using NHibernateTest.Model;
using NHibernateTest.Manager;
namespace NHibernateTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //添加数据
            //UserManager userManager = new UserManager();
            //User user = new User { Username = "mmmm", Password = "00000" };
            //userManager.Add(user);
            //更新数据
            //UserManager userManager = new UserManager();
            //User user = new User { Id=29 , Username="哈哈",Password="0000123" };
            //userManager.Updata(user);
            //删除数据
            //UserManager userManager = new UserManager();
            //User user = new User { Id = 29};
            //userManager.Delete(user);
            //根据用户ID查询数据
            //UserManager userManager = new UserManager();
            //User user = userManager.GetUserById(11);
            //Console.WriteLine(user.Username+" "+user.Password);
            //根据用户名查询数据
            //UserManager userManager = new UserManager();
            //User user = userManager.GetUserByUsername("wer23");
            //Console.WriteLine(user.Id + " " + user.Password);
            //查询表里的所有数据
            //UserManager userManager = new UserManager();
            //ICollection<User> users = userManager.GetAllUsers();
            //foreach (var item in users)
            //{
            //    Console.WriteLine(item.Id+" "+item.Username+" "+item.Password);
            //}
            //验证用户名密码是否存在
            UserManager userManager = new UserManager();
            Console.WriteLine(userManager.VerifyUser("wer","123"));//如果存在返回true,不存在返回fasle
            Console.ReadKey();
        }
    }
}

拓展

关于Restrictions的各种用法: