DOC下载:http://fastspring.googlecode.com/files/Spring.NET_NHibernate....NET.doc
代码下载:http://fastspring.googlecode.com/files/Spring.Net_NHibernate_Cn_Book.zip
目 录
实战C#.NET编程----Spring.NET & NHibernate从入门到精通-- 1
第一章 Visual C# .NET 入门指南-- 3
一、 C# 简介-- 3
二、 使用Visual Studio 开始C# 项目-- 3
步骤 1. 开始项目-- 4
步骤 2. Hello, World!- 5
步骤 3. 程序结构-- 7
步骤 4. 控制台输入-- 8
步骤 5. 使用数组-- 9
步骤 6. 文件输入/输出-- 10
步骤 7. 创建函数-- 13
步骤 8. 使用调试器-- 15
小结-- 17
第二章 面向对像ORM- 18
一、 什么是ORM- 18
二、 为什么需要ORM- 19
三、 流行的ORM框架简介-- 19
第三章 Spring.NET入门-- 20
一、 Spring.NET概览-- 20
二、 第一个Spring.NET的程序-- 22
第四章 NHibernate入门-- 25
一、 什么是Nhibernate- 25
二、 Nhibernate概述-- 25
三、 第一个NHibernate 程序-- 28
第五章 Spring.NET 与 NHibernate 的整合-- 34
一、 建立新的项目(SpringNHibernateSample)- 35
二、 添加NHibernate程序-- 35
三、 添加Spring.NET的程序-- 35
四、 添加Spring.NET为NHibernate的容器配置-- 38
五、 编写测试程序代码-- 41
六、 测试并查看结果-- 43
第六章 深入Spring.NET 与 NHibernate开发-- 43
第七章 项目实战----办公自动化系统-- 43
第八章 结束语-- 43
首先简单介绍下几个术语:
1.O/R Mapping
对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。 简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将。Net程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示者额外的执行开销;然而,如果ORM作为一种中间件实现,则会有很多机会做优化,而这些在手写的持久层并不存在。
2.NHibernate
在今日的企业环境中,把面向对象的软件和关系数据库一起使用可能是相当麻烦和浪费时间的.NHibernate不仅仅管理.NET类到数据库表的映射(包括.NET 数据类型到SQL数据类型的映射),还提供数据查询和获取数据的方法,可以大幅度减少开发时人工使用SQL和ADO.NET处理数据的时间。
NHibernate的目标主要是用于与数据持久化相关的编程任务,能够使开发人员从原来枯燥的SQL语句的编写中解放出来,解放出来的精力可以让开发人员投入到业务逻辑的实现上。
3.例子
现在我就用一个简单的例子来向大家说明,在vs2005下如何利用spring.net框架的IOC机制通过O/R mapping机制对数据库进行访问。
1. 建立一个c/s项目命名为Springs,并且引入相应的spring.net的命名空间(如图1)[在这里需要说明的我们用的是spring.net1..2的版本,nhibernate为1.2的版本]
2. 用sqlserver2000创建一个名为Test的数据库,并且在这个数据库中建立一个名字为myuser的数据表:
列名 |
类型 |
长度 |
|
userid(主键) |
Int |
4 |
|
username |
varchar |
20 |
|
userpassword |
varchar |
20 |
|
Useremail |
Varchar |
20 |
|
数据表建立好了以后,我们要做的就是在项目中为此表建立一个实体映射类
3. 建立一个实体映射类MyUser.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace Springs.model//从这我们可以知道类的命名空间,以后将不再重复
{
public class MyUser
{
private int userid;
public int Userid
{
get { return userid; }
set { userid = value; }
}
private String username;
public String Username
{
get { return username; }
set { username = value; }
}
private String userpassword;
public String Userpassword
{
get { return userpassword; }
set { userpassword = value; }
}
private String useremail;
public String Useremail
{
get { return useremail; }
set { useremail = value; }
}
}
}
4. 建立起表与实体类之间的关系MyUser.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Springs.model.MyUser,Springs" table="myuser" lazy="false">
<id name="Userid" column="userid" type="Int32">
<generator class="native" />
</id>
<property name="Username" column="username" type="String" length="20" />
<property name="Userpassword" column="userpassword" type="String" length="20" />
<property name="Useremail" column="useremail" type="String" length="20"></property>
</class>
</hibernate-mapping>
至此,我们已经完成了数据表和实体类之间的映射关系
5. 建立一个服务接口UserService.cs
using System;
using System.Collections.Generic;
using System.Text;
using Springs.model;
using System.Data;
namespace Springs.service
{
public interface UserService
{
void insert(MyUser user);
}
}
6. 实现UserService接口(UserServiceImp.cs)
using Spring.Data.NHibernate.Support;
using Springs.service;
using Springs.model;
using System.Configuration;
using Spring.Context;
using System.Data;
using System.Data.Sql;
using System.Data.SqlClient;
using NHibernate;
namespace Springs.serviceimp
{
public class UserServiceImp:HibernateDaoSupport,UserService
{
public void insert(MyUser user)
{
this.HibernateTemplate.Save(user);
}
}
}
在这里我需要解释的是,对于HibernateDaoSupport这个类来说我们在前面的过程中并没有提到,这个类是Spring.net框架中实现好的类,我们只要实现它,并且在spring.net的xml文件中(稍候将会看到)进行相应的配置,就可以通过它来调用HibernateTemplate对数据库进行映射操作了。
7.编写一个可以利用UserService服务的类UserManager.cs
using System;
using System.Collections.Generic;
using System.Text;
using Springs.serviceimp;
using Springs.service;
using Springs.model;
namespace Springs.usermanager
{
public class UserManager
{
private UserService us;
public UserService Us
{
get { return us; }
set { us = value; }
}
public void insertUser()
{
MyUser user = new MyUser();
user.Username = "zhenxin";
user.Userpassword = "hahaha";
user.Useremail = "[email protected]";
us.insert(user);
}
}
}
在这里我们利用属性形式(如果不明白什么是属性形式注入,请参看《业务规则层案例4.0.1》)将服务UserService注入在了UserManager中(稍候将看到spring.net的xml文件),在insertUser()方法中调用UserService的服务,直接对数据实体类MyUser进行操作。
为了我们可以很好的管理所有的服务,我们需要创建一个服务器容器ServiceContainer,在这里,我们可以随时调用我们需要的服务,创建这个类的好处是,可以对服务进行管理,方便于调用。
using System;
using System.Collections.Generic;
using System.Text;
using Spring.Context;
using System.Configuration;
using Spring.Context.Support;
using Springs.service;
namespace Springs.tools
{
public class ServiceContainer
{
private UserService userServices;
public static IApplicationContext context;
private static ServiceContainer serviceContainer = null;
private ServiceContainer()
{
}
public static ServiceContainer Servicecontainer
{
get
{
if (serviceContainer == null)
{
serviceContainer = new ServiceContainer();
context = ContextRegistry.GetContext();
}
return serviceContainer;
}
}
public UserService UserServices
{
get
{
userServices = context.GetObject("UserService") as UserService;
return userServices;
//通过IOC注入在这里得到UserService实例对象
}
}
}
}
此类为设计成单例的原因是,只允许一个ServiceContainer的产生,所有的服务都通过这一个ServiceContainer进行调用。
7. 配置app.config文件
为了将spring.net框架加入到我们的项目中我们需要在项目启动的时候就要对spring.net 进行加载,我们将spring.net框架的xml文件单独放在一个文件user_spring.xml中,在app.config中我们只要引用就可以了。
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context>
<resource uri="http://www.cnblogs.com/user_spring.xml"></resource>//引用文件
<resource uri="config://spring/objects"/>
</context>
<objects xmlns="http://www.springframework.net"/>
</spring>
<appSettings/>
<connectionStrings/>
</configuration>
8.配置user_spring.xml
这是我们的核心配置文件。
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
<object id="DbProvider" type="Spring.Data.Common.DbProviderFactoryObject,Spring.Data">
<property name="Provider" value="SqlServer-2.0"/>
<property name="ConnectionString" value="Data Source=.;Database=Test;User ID=sa;Password=;Trusted_Connection=False" />
</object>
<object id="SessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12">
<property name="DbProvider" ref="DbProvider" />
<property name="MappingAssemblies">
<list>
<value>Springs</value>
</list>
</property>
<property name="HibernateProperties">
<dictionary>
<entry key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" />
<entry key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" />
<entry key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
<entry key="show_sql" value="true" />
</dictionary>
</property>
</object>
<object id="UserService" type="Springs.serviceimp.UserServiceImp">
<property name="SessionFactory" ref="SessionFactory" />
</object>
<object id="UserManager" type="Springs.usermanager.UserManager">
<property name="Us" ref="UserService" />
</object>
</objects>
在这个文件中有SessoionFactory和DbProvider这两个节点的配置应该多多注意下。同时还注入了UserService服务,还有UserManager这个将服务以属性方式注入到自身里的类。
9.测试
(1) 第一种:从ServiceContainer中得到服务,对数据库进行插入操作
using Spring.Context;
using System.Configuration;
using Springs.usermanager;
using Springs.service;
using Springs.model;
using Spring.Core;
using Spring.Aop;
using Spring.Context.Support;
using Springs.tools;
private void Form1_Load(object sender, EventArgs e)
{
UserService sc= ServiceContainer.Servicecontainer.UserServices;
MyUser user = new MyUser();
user.Username = "XXXXXXX";
user.Userpassword = "hahaha";
user.Useremail = "[email protected]";
sc.insert(user);
}
(2)第二种:通过ServiceContainer调用服务,对数据库进行插入操作
private void Form1_Load(object sender, EventArgs e)
{
IApplicationContext context= ContextRegistry.GetContext();
UserManager um = (UserManager)context.GetObject("UserManager");
um.insertUser();
}
10.功能扩展
在上述的例子中展示了spring.net结合nhibernate集合框架对数据库进行插入操作的实现,现在要将此功能扩展,使读者更加深刻的体会到nhibernate是如何对数据库进行操作的。下面是扩展后的小例子,我们可以在这里进行增、删、该、查的功能
(1) 实现全部查询功能
当你单击显示数据的时候,所有从数据库中得到的数据将会全部显示在上述的dataGridView中,显示如下:
功能的实现还是通过UserServiceImp来实现UserService中定义的SelectAll()方法代码片断如下:
public IList SelectAll() {
//第一种实现方式
// IQuery q = this.Session.CreateQuery("From MyUser");
//IList list=q.List();
//return list;
//第二种实现方式
IList list =this.HibernateTemplate.LoadAll(typeof(MyUser));
return list;
}
在这里我要说明的是:这里有两种方式来实现查询,第一种是通过功能强大的hql查询语言,第二种是通过HibernateTemplate.LoadAll()方法来进行。
第一种方式的优点是:查询功能灵活,可以根据用户来自定义查询语句,可以实现多条查询或者模糊查询。但是缺点是,增加了程序员的工作量,因为要自己写查询语句。
第二种方式的优点是:可以简便的实现查询功能,代码的规则统一,但是缺点是功能不够强大,没有办法通过用户自定义来编写需要的查询语句。
(2)实现删除功能
同样的删除功能的实现也是通过,在UserServiceImp中实现UsersService接口中的deleteById()方法(这只是一个方法名称没有具体意义)
public void deleteById(MyUser user)
{
this.HibernateTemplate.Delete(user);
}
在这里需要指出(以此程序为例)的我们在传递参数MyUser的时候,不需要将MyUser的所有属性赋值,我们只需要将这个实体类中对应映射数据表中的主键的属性赋值就可以完成效果,这样也大大地简化了程序的代码量。
(3) 实现按条件查询
当按下“按ID查询”出现一条记录
在UserServiceImp中的代码片断是:
public MyUser selectOneById(int userid)
{ //第一种方式
//IQuery q = this.Session.CreateQuery("From MyUser where Userid=?");
//q.SetInt32(0, userid);
//IList list = q.List();
//MyUser user = (MyUser)list[0];
//return user;
//第二种方式
return HibernateTemplate.Load(typeof(MyUser), userid) as MyUser;
}
在第一种实现方式中,展现了使用hql语句的传参实现方式,所以可以利用hql这种实现方式,进行多条件查找,和模糊查找,弹性非常好。
(4)关于更新
关于更新其实和插入的方式差不多,在这里就不赘述了
11.关于NHibernate对象关联映射
现在我们以另外一个小例子来讲述以下什么是对象关联映射。
在数据库的表中避免不了要在表和表之间产生关联,一对多的关系最为常见,比如说一张存储父亲信息的表中,会有很多的父亲信息,当然,对于这个表可能会对应一张存储儿子的表,但是很显然,对于一个父亲而言,可能会对应很多的儿子这样就形成了一对多的关系,但是我们要在实体映射中如何体现这样的关系呢?
(1)首先我们需要在数据库中建立起这样的对应关系
在Parent.cs中:
public class Parent
{
private int parentId;
public int ParentId
{
get { return parentId; }
set { parentId = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private IList children;
public IList Children
{
get { return children; }
set { children = value; }
}
}
在Child.cs中的代码:
public class Child
{
private int childId;
public int ChildId
{
get { return childId; }
set { childId = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private int parentId;
private Parent parent;
public Parent Parent
{
get { return parent; }
set { parent = value; }
}
}
请仔细观察中间的属性字段。
Parent.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="路径.Parent,项目名称" table="T_Parent">
<id name="ParentId" column="ParentId" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<property column="Name" type="String" name="Name" length="64" />
<set name="Children" cascade="all" inverse="true" lazy="true">
<key column="ParentId"/>
<one-to-many class="路径/Child,项目名称"/>
</set>
</class>
</hibernate-mapping>
Child.hbm.xml
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="路径.Child,项目名称" table="T_Child">
<id name="ChildId" column="ChildId" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<property column="Name" type="String" name="Name" length="64" />
<many-to-one name="Parent" column="ParentId" class="路径.Parent,项目名称 />
</class>
</hibernate-mapping>
在NHibernate配置文件中使用<set>, <list>, <map>, <bag>, <array> 和 <primitive-array>等元素来定义集合。<bag>是典型的一个,代码中我们用IList和它对应。我们以后会详细讲集合这个话题。
lazy表示允许延迟加载。表示在需要使用时才加载需要的数据。例如使用lazy时我们Load一个Parent他的Children为空,只有我们访问它的某一个Child时数据才会被加载;而不设置lazy我们Load一个Parent时其Children将同时加载。注意:使用lazy加载必须保证对应ISession的打开,否则懒加载会失败。
one-to-many可以设置单向和双向映射,设置单向时Child一段不设置many-to-one,而设置了ParentId的属性。
双向映射需要设置inverse而单向不需要。
单项映射在cascade时会对把T_Child的ParentId使用Update为Null的操作。
建议尽量使用双向映射。
http://www.cnblogs.com/i-miss-you/articles/1606976.htm
由于要通过spring.,net中的O/R mapping 机制对数据库进行访问,所以我们需要运用nhibernate这个数据持久层的框架(这个框架的命名空间在步骤1中已经实现)