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 = ; i < ; 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(, ) - 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久时间,以后还要多做练习。
Nhibernate随手记(1)的更多相关文章
- .Net下的 ORM框架介紹
在.NET平台下,关于数据持久层框架非常多,本文主要对如下几种做简要的介绍并推荐一些学习的资源: 1.NHibernate 2.NBear 3.Castle ActiveRecord 4.iBATIS ...
- 几种.NET平台数据持久化框架介绍
原文连接:http://yuxnet.blog.163.com/blog/static/164863495201131532223362/ 在.NET平台下,关于数据持久层框架非常多,本文主要对如下几 ...
- .NET平台下,关于数据持久层框架
在.NET平台下,关于数据持久层框架非常多,本文主要对如下几种做简要的介绍并推荐一些学习的资源: 1.NHibernate 2.NBear 3.Castle ActiveRecord 4.iBATIS ...
- .NET开源项目介绍及资源推荐:数据持久层
在.NET平台下,关于数据持久层框架非常多,本文主要对如下几种做简要的介绍并推荐一些学习的资源: 1.NHibernate 2.NBear 3.Castle ActiveRecord 4.iBATIS ...
- Nhibernate1
Nhibernate随手记(1) 学习Nhibernate的萌芽 今早有群里有人问Nhibernate的问题,没学过,刚好来了兴趣,无意很快在园子里下载到了一本Nhibernate3.0的电子书,内容 ...
- Net下的 ORM框架介紹(转)
http://www.cnblogs.com/zhaoyx/articles/1896638.html 在.NET平台下,关于数据持久层框架非常多,本文主要对如下几种做简要的介绍并推荐一些学习的资源: ...
- Nhibernate的Session管理
参考:http://www.cnblogs.com/renrenqq/archive/2006/08/04/467688.html 但这个方法还不能解决Session缓存问题,由于创建Session需 ...
- "NHibernate.Exceptions.GenericADOException: could not load an entity" 解决方案
今天,测试一个项目的时候,抛出了这个莫名其妙的异常,然后就开始了一天的调试之旅... 花了很长时间,没有从代码找出任何问题... 那么到底哪里出问题呢? 根据下面那段长长的错误日志: -- ::, ...
- Linux.NET实战手记—自己动手改泥鳅(上)
各位读者大家好,不知各位读者有否阅读在下的前一个系列<Linux.NET 学习手记>,在前一个系列中,我们从Linux中Mono的编译安装开始,到Jexus服务器的介绍,以及如何在Linu ...
随机推荐
- Don’t Use Accessor Methods in Initializer Methods and dealloc 【初始化和dealloc方法中不要调用属性的存取方法,而要直接调用 _实例变量】
1.问题: 在dealloc方法中使用[self.xxx release]和[xxx release]的区别? 用Xcode的Analyze分析我的Project,会列出一堆如下的提示:Inco ...
- COGS396. [网络流24题]魔术球问题(简化版
问题描述: 假设有n根柱子,现要按下述规则在这n根柱子中依次放入编号为 1,2,3,4......的球. (1)每次只能在某根柱子的最上面放球. (2)在同一根柱子中,任何2个相邻球的编号之和为完全平 ...
- openerp7 时区问题
由于目前openerp 的时区,读取的是UTC 时间,而我国本地时间比UTC 快8小时,这个问题就导致:写入数据库的时候时间相差8小时,以及Openerp日志输出时间格式也相差8小时和 前端显示时间的 ...
- win7使用iis并搭建 图片服务器
1.打开控制面板 2.程序-卸载程序 3.点击左边的 打开或关闭windows功能 4.如下图所示,找到internet信息服务勾选.顺便把FTP服务器也全部勾选了,后面会用到 5.进入 控制面板 – ...
- js实现文本框中内容的放大显示
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- Here String 中不该进行分词
我们知道,在 Shell 中,一个变量在被展开后,如果它没有被双引号包围起来,那么它展开后的值还会进行一次分词(word splitting,或者叫拆词,分词这个术语已经被搜索引擎相关技术占用了)操作 ...
- NGUI 学习笔记
1.NGUI中UI的深度关系(新版NGUI 3.9): 在同一个Panel中,不管同不同Altas,各个UI的顺序受Depth影响 在不同Panel中,UI的顺序受Panel的Depth影响 例如Pa ...
- Android锁屏后数据改变的解决方案
如果一个界面设置成横屏,那么锁屏再开启之后,会重新执行一遍onCreate()方法.对于这个问题的解决方案如下: 只需要在Menifest文件的activity相应标签下添加这行代码即可: andro ...
- SQL 查找表名 字段名
转载:http://www.accessoft.com/article-show.asp?id=6135 经常碰到一些忘记表名称的情况,此时只记得个大概,此时可通过查询系统表Sysobjects找到所 ...
- PHP变量作用域(花括号、global、闭包)
花括号 很多语言都以花括号作为作用域界限,PHP中只有函数的花括号才构成新的作用域. <?php if (True) { $a = 'var a'; } var_dump($a); for ($ ...