NHibernate是一个面向.NET环境的对象/关系数据库映射工具。对象/关系数据库映射(object/relational mapping,ORM)这个术语表示一种技术,用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。
NHibernate 从数据库底层来持久化你的.Net 对象到关系型数据库。NHibernate 为你处理这些,远胜于你不得不写SQL去从数据库存取对象。你的代码仅仅和对象关联,NHibernat 自动产生SQL语句,并确保对象提交到正确的表和字段中去。
官网下载: http://nhibernate.info/
NHibernate官方教程: http://nhibernate.info/doc/tutorials/first-nh-app/your-first-nhibernate-based-application.html(基于Server SQL的连接教程,但是原理一样)
Code Project里面的教程示例: https://www.codeproject.com/articles/26123/nhibernate-and-mysql-a-simple-example
这里推荐一个网站Sourceforge: https://sourceforge.net/(很多开源插件都放在这个网站)
下载后直接在Required_Bins文件下找到NHibernate.dll将其添加入VS里面的引用就OK了
配置NHibernate
在这里我先摆上自己创建的数据库,然后开始配置映射
我们现在必须告诉NHibernate我们想要使用哪个数据库产品,并以连接字符串的形式提供连接细节。NHibernate支持许多数据库产品!我们使用的是MySQL,所以我们先添加一个XML文本,并将其命名为 hibernate.cfg.xml(固定命名)然后再xml文件下添加以下配置。
NHibernate.Connection.DriverConnectionProvider
NHibernate.Dialect.MySQL5Dialect
NHibernate.Driver.MySqlDataDriver
Server=localhost;Database=mygamedb;User ID=root;Password=root;
true
使用这个配置文件,我们告诉NHibernate我们要使用MySQL作为目标数据库
connection.provider: 设置NHibernate要连接到数据库的连接提供程序。
dialect :陈述了NHibernate类名,可以实现某些依赖平台的功能,在这种情况下,由于我使用MySQL 5,所以明显的选择是MySQL5Dialect
connection.driver_class: 设置哪个驱动程序应该使用,在这种情况下,当使用MySQL时,MySqlDataDriver是一个合乎逻辑的选择
connection.connection_string: 是数据库的连接字符串。
配置文件的映射部分告诉NHibernate哪些映射文件用于对象/关系映射
配置完后,我们将其属性“ 复制到输出目录 ”设置为“ 始终复制 ”。
配置数据的映射
配置对应的数据库后我们开始创建一个模型的类,首先要对应数据库中的数据的话我们需要创建一个类去保存数据库中的数据。这里我们先在项目下先创建出一个文件夹命名为Model,然后在Model文件夹下创建一个类,为了与数据库中对应的User表相对应我们在这里给类命名为User,然后写入和数据库中相对应的表中的属性,如下
public class User
{
//对应数据库的属性
public virtual int Id { get; set; }
public virtual string Username { get; set; }
public virtual string Password { get; set; }
public virtual DateTime Registerdate { get; set; }
}
为了能够使用User该类,有必要创建一个映射文件,其中包含NHibernate用于对象/关系映射的元数据,即连接类声明,属性到列和数据库表中的键。然后这个时候我们还需要一个配置文件,用来映射数据库中的属性到类库中,我们先创建一个Mappings文件夹,然后再Mappings文件夹下创建XML文件并且命名为User.hbm.xml,然后写入以下配置信息
NHibernate/Database(数据库)/.NET里面的各种类型的声明 :http://nhibernate.info/doc/nhibernate-reference/mapping.html#mapping-types
映射文件包含一组节点,其简短版本的解释是:
hibernate-mapping:声明这是一个hibernate映射文件,该xmlns属性声明应该使用的XML命名空间
class: 指出此映射连接到的持久类:
该name属性必须指定完全限定的.Net类名称,并且还必须包含程序集名称
该table属性命名数据库中的表名
id: 是描述数据库表中主键列的节点
该name属性告诉NHibernate永久类中的哪个属性被使用
该column属性告诉数据库表中的哪个列是主键
该type属性告诉NHibernate数据库类型,这在大多数情况下应该被自动检索,但是我发现这是一个问题,因此指定类型
generator:是id节点的必需子元素,该class属性声明应该使用哪个.NET类来为持久化类的实例生成唯一标识符,该类可能是应用程序的特定实现,也可以是其中一个NHibernate提供的内置实现,在我的例子中是依赖于底层数据库的功能的本地类,对于MySQL,使用具有自动增量功能的标识列功能
property: 是描述与数据库表中的列相对应的持久性类属性的一个或多个元素,在我的情况下,它仅由一列组成,因此相应地映射
该name属性告诉该类中的哪个属性被使用
该column属性对应于列名在数据库
该type属性告诉NHibernate数据库列类型,这在大多数情况下应该被自动检测,但是如前所述,可能会有一些麻烦
该映射文件被添加到我的项目根目录中,并且我发现,将XML文件的构建操作设置为“嵌入式资源”,因为这样可以使NHibernate在运行时解析这一点,从而简化了所需的编码当使用映射功能。
所以我们这里将这个配置文件的生成操作设置为嵌入的资源
插入数据
var configuration = new Configuration();
configuration.Configure();//用来解析nibernate.cfg.xml的,解析数据库的连接文件的
configuration.AddAssembly("NHibernateController");//添加程序集 解析映射文件 User.hbm.xml
ISessionFactory sessionFactory = null;
ISession session = null;
try
{
sessionFactory = configuration.BuildSessionFactory();
session = sessionFactory.OpenSession();//打开一个跟数据库的回话 ,跟数据库的一个连接
//添加数据
User user = new User() { Username = "World" ,Password="1579"};//插入数据World
session.Save(user);//并且保存起来
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally {
if (sessionFactory!=null)
{
sessionFactory.Close();
}
if (session!=null)
{
session.Close();
}
}
这时候我们就可以看到数据已经插入数据库了
事务
那么什么是事务呢,我们来看看,下面画个图理解下
比如这张图就是一个事务,里面有三个事件,当事件一插入执行成功,事件二由于一些原因没能执行成功,这个时候事件一就要返回成原来的数据,当事件一事件二事件三都执行成功的时候才会去修改数据库中的数据,这就是事务。下面实验下
using NHibernate;
using NHibernate.Cfg;
namespace NHibernateController
{
class Program
{
var configuration = new Configuration();
configuration.Configure();//用来解析nibernate.cfg.xml的,解析数据库的连接文件的
configuration.AddAssembly("NHibernateController");//添加程序集 解析映射文件 User.hbm.xml
ISessionFactory sessionFactory = null;
ISession session = null;
ITransaction transaction = null;
try
{
sessionFactory = configuration.BuildSessionFactory();
session = sessionFactory.OpenSession();//打开一个跟数据库的回话 ,跟数据库的一个连接
//事务
transaction= session.BeginTransaction();
//进行操作
User user1 = new User() { Username = "EasyA", Password = "1579" };//插入数据
User user2 = new User() { Username = "EasyB", Password = "544" };
session.Save(user1);
session.Save(user2);
transaction.Commit();//进行提交
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally {
if (transaction != null)
{
transaction.Dispose();
}
if (session != null)
{
session.Close();
}
if (sessionFactory!=null)
{
sessionFactory.Close();
}
}
}
}
这个时候是成功插入的,因为条件都满足,但是如果我们插入的第二个数据不成功的话那么第一个数据也不会改变,例如我们数据库中设置了限制用户名不能相等,这个时候我们插入的第二条数据在数据库中已经存在了,那么这个时候第一条数据也会执行失败。数据不会修改。
管理会话工厂(对获取数据库以及增删改查进行一层封装)
那么按照上面那种方法每次都需要去创建Configuration方法会非常麻烦,下面我们去把这个类封装下,首先创建一个NhibernateHelper类,写入以下代码
using NHibernate;
using NHibernate.Cfg;
namespace NHibernateController
{
class NhibernateHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory==null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly("NHibernateController");
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
public static ISession OpenSession()
{
return SessionFactory.OpenSession();
}
}
}
然后我们还需要创建一个管理User表的文件夹里面创建一个接口IUserManager,一个实现接口的类UserManager,然后我们开始写入
using System.Collections.Generic;
using NHibernateController.Model;
namespace NHibernateController.Manager
{
//接口
using System.Collections.Generic;
using NHibernateController.Model;
namespace NHibernateController.Manager
{
interface IUserManager
{
void Add(User ser);
void Update(User user);//更新数据
void Remove(User user); //删除数据
User GetById(int id); //根据ID获取数据
User GetByUsername(string username); //根据username获取数据
ICollection GetAllUsers(); //获取所有数据
bool VerifyUser(string username, string password);//验证用户密码
}
}
//实现接口
using System.Collections.Generic;
using NHibernateController.Model;
using NHibernate;
using NHibernate.Criterion;
namespace NHibernateController.Manager
{
class UserManager : IUserManager
{
public void Add(User user)
{
//也可使用成一个事务
using (ISession session = NhibernateHelper.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())//事务的开始
{
//进行操作
session.Save(user);
transaction.Commit();//事物的提交
}
}
}
public ICollection GetAllUsers()
{
using (ISession session = NhibernateHelper.OpenSession())
{
//Restrictions.Eq()表示添加查询条件
// criteria.UniqueResult();得到唯一的结果,返回的是User对象
IList users = session.CreateCriteria(typeof(User)).List();
return users;
}
}
public User GetById(int id)//查询条件不会更改数据所以不需要使用事务
{
using (ISession session = NhibernateHelper.OpenSession())
{
//进行操作
User user = session.Get(id);//删除数据
return user;
}
}
public User GetByUsername(string username)
{
using (ISession session = NhibernateHelper.OpenSession())
{
//Restrictions.Eq()表示添加查询条件
// criteria.UniqueResult();得到唯一的结果,返回的是User对象
User user = session.CreateCriteria(typeof(User)).Add(Restrictions.Eq("Username", username)).UniqueResult();//创建一个配置文件
return user;
}
}
public void Remove(User user)
{
using (ISession session = NhibernateHelper.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())//事务的开始
{
//进行操作
session.Delete(user);//删除数据
transaction.Commit();//事物的提交
}
}
}
public void Update(User user)
{
using (ISession session = NhibernateHelper.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())//事务的开始
{
//进行操作
session.Update(user);//更新数据
transaction.Commit();//事物的提交
}
}
}
public bool VerifyUser(string username, string password)
{
using (ISession session = NhibernateHelper.OpenSession())
{
IList users = session.CreateCriteria(typeof(User)).List();
User user = session.CreateCriteria(typeof(User))
.Add(Restrictions.Eq("Username", username))
.Add(Restrictions.Eq("Password", password))
.UniqueResult();
if (user == null) return false;
return true ;
}
}
}
}
这样我们每次直接使用封装好的方法就OK了。非常方便
using System;
using System.Collections.Generic;
using NHibernateController.Model;
using NHibernateController.Manager;
namespace NHibernateController
{
class Program
{
static void Main(string[] args)
{
IUserManager userManager = new UserManager();
////添加
//User user = new User() { Id = 8, Username = "sadasd", Password = "15654" };
//userManager.Add(user);
////更新
//userManager.Update(user);
////删除
//userManager.Remove(user);
////根据Id查询值
//Console.WriteLine(userManager.GetById(8).Password + userManager.GetById(8).Username);
////根据Username进行查询
//Console.WriteLine(userManager.GetByUsername("Sure").Password);
////输出所有表里面的数据
//ICollection users = userManager.GetAllUsers();
//foreach (User u in users)
//{
// Console.WriteLine(u.Username + " " + u.Password);
//}
//验证账号密码是否正确
Console.WriteLine(userManager.VerifyUser("Sure","157"));
Console.ReadKey();
}
}
}
下面是我们查询数据库中所有数据的结果
对照一下用户名和密码都没问题