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)
注意:表的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; }
}
注意:属性需为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>
注意: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>
注意: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();
}
}
}
}
5、在解决方案中添加控制台项目,在该项目中引用类库, program.cs如下:
static void Main(string[] args)
{
IStudentDao studentDao = new StudentDao();
Student student = new Student() { Id = , Age = , Name = "yang", Score = }; //var obj = studentDao.Save(student);
//Console.WriteLine(obj.ToString()); Student student2 = studentDao.Get();
Console.WriteLine(student2.Score);
student2.Score = ;
studentDao.SaveOrUpdate(student2);
student2 = studentDao.Get();
Console.WriteLine(student2.Score); //Student student2 = studentDao.Get(1);
//Console.WriteLine(student2.Score);
//studentDao.Delete(student2); Console.ReadKey();
}
运行该项目,即可进行测试
(本例包含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)
)
注意:在配置文件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; }
}
<?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>
需要注意的是: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>();
Console.WriteLine(family.Adress) ;
Console.WriteLine(family.Student.Name);
tran.Commit();
}
}
}
}
源码中包含双向引用的实例ChildTest,对应SQL
create table T_Child
(
ChildID int IDENTITY(1,1),
Name varchar(25)
) create table T_Mom
(
MomID int,
Name varchar(25)
)
关于一对一关系需注意的事项:
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)
)
注意:配置中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; }
}
<?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>
需要注意的是: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>();
Console.WriteLine(family.Adress);
Console.WriteLine(family.Students.Count);
tran.Commit();
}
}
}
}
源码中包含了多对一(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)
)
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)
)
关于一对多,多对一关系需注意的事项:
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
)
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; }
}
<?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>
需要注意的是: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>();
Console.WriteLine(role.Name);
Console.WriteLine(role.Users.Count);
tran.Commit();
}
}
}
}
关于多对多,注意<bag>默认的cascade为none,因此需显式指定为all,方可保存临时态(Transient)实例
关于NHIbernate详细介绍可参考刘冬的博客
NHibernate简单使用介绍的更多相关文章
- JS图表组件 highcharts 简单的介绍
把highcharts拿来做个简单的介绍,希望更多的朋友可以用到这个用来做图表的js插件. preparation Highcharts Highcharts是一个制作图表的纯Javascript类库 ...
- vue学习笔记(二)——简单的介绍以及安装
学习编程需要的是 API+不断地练习^_^ Vue官网:https://cn.vuejs.org/ 菜鸟教程:http://www.runoob.com/vue2/vue-tutorial.html ...
- EVE-NG简单入门介绍
此篇文章简单的介绍下模拟器EVE-NG的使用,具体包括Dynamips设备导入与运行,IOL设备的导入与运行,QEMU设备的导入与运行,客户端软件的安装,物理网络与虚拟网络的结合等. 一.导入镜像 D ...
- Mybatis缓存(1)--------系统缓存及简单配置介绍
前言 Mybatis的缓存主要有两种: 系统缓存,也就是我们一级缓存与二级缓存: 自定义的缓存,比如Redis.Enhance等,需要额外的单独配置与实现,具体日后主要学习介绍. 在这里主要记录系统缓 ...
- GIT 分布式版本控制系统的简单使用介绍
GIT 分布式版本控制系统的简单使用介绍 1.GIT的概念Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git 与 SVN 区别:1. GIT不仅仅是个版本控制系统,它 ...
- 我的Android进阶之旅】GitHub 上排名前 100 的 Android 开源库进行简单的介绍
GitHub Android Libraries Top 100 简介 本文转载于:https://github.com/Freelander/Android_Data/blob/master/And ...
- MonkeyTest简单实用介绍
什么是Monkeytest? monkey测试是Android平台自动化测试的一种手段,通过Monkey程序模拟用户触摸屏幕.滑动Trackball.按键灯操作来对设备上的程序进行压力测试,检测程序发 ...
- CCNA网络工程师学习进程(6)vlan相关协议的配置与路由器简单配置介绍
前面已经介绍了大部分与vlan技术相关的交换机的协议的配置,更深层次的还有STP协议和以太网端口聚合技术,接着还会简单介绍一下路由器的基本应用. (1)STP(Spanning-tre ...
- GitHub 上排名前 100 的 Android 开源库进行简单的介绍
若有任何疑问可通过邮件或微博联系我 项目名称 项目简介 1. react-native 这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开 ...
随机推荐
- 一份关于Swift语言学习资源的整理文件
一份关于Swift语言学习资源的整理文件 周银辉 在这里下载 https://github.com/ipader/SwiftGuide
- C# Winform程序把引用的dll放到指定目录
如果项目引用了很多dll,发布的时候放同一目录会很乱,这时候可以用privatePath后面指定搜索的dll文件夹,多个用;分隔 另外,发现在配置文件夹中 configSource 也是可以指定目录的 ...
- SQLite剖析之异步IO模式、共享缓存模式和解锁通知
1.异步I/O模式 通常,当SQLite写一个数据库文件时,会等待,直到写操作完成,然后控制返回到调用程序.相比于CPU操作,写文件系统是非常耗时的,这是一个性能瓶颈.异步I/O后端是SQLit ...
- Jquery自定义插件之$.extend()、$.fn和$.fn.extend()
jquery插件的种类: 1.对象级别的插件开发,即给jQuery对象添加方法,封装对象方法的插件,如:parent().appendTo() 2.一种是类级别的插件开发,即给jQuery添加新的全局 ...
- [React] 多组件生命周期转换关系
前段时间一直在基于React做开发,最近得空做一些总结,防止以后踩坑. 言归正传,React生命周期是React组件运行的基础,本文主要是归纳多组件平行.嵌套时,生命周期转换关系. 生命周期 Reac ...
- 基于MST的立体匹配及相关改进(A Non-Local Cost Aggregation Method for Stereo Matching)
怀着很纠结的心情来总结这篇论文,这主要是因为作者提虽然供了源代码,但是我并没有仔细去深究他的code,只是把他的算法加进了自己的项目.希望以后有时间能把MST这一结构自己编程实现!! 论文题目是基于非 ...
- 教你一招:在PowerPoint中自定义可输入文本的占位符
日常生活中,当我们设计多媒体课件时,默认的版式其实已经够用了.但是,很多时候,我们需要更加个性一点,所以,我们需要自定义很多东西.本文介绍在PowerPoint中自定义可输入文本的占位符. 一.占位符 ...
- TYVJ1338 QQ农场
时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 Sandytea前段时间沉迷于QQ农场中……一天夜里,他梦见来到好友X的农场上…… 描述 这个农场和游戏中略有 ...
- React Native 开发之 (01) 配置开发环境
一 React Native React Native 是由Facebook发布的开源框架,着力于提高多平台开发的开发效率 —— 仅需学习一次,编写任何平台.(Learn once, write an ...
- <<< Java提取网页源码
package com.sevennight; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io ...