MVC3+NHibernate项目实战(二) :数据库访问层
我们现在使用NHibernate一步一步来构建数据库访问层.
一.首先建立Blog.Model:实体层项目
(1)先建立EntityBase实体基类,然后所有的实体都继承该类;
View Code
namespace Blog.Model { public class EntityBase { public virtual int Id { get; set; } public virtual bool IsDelete { get; set; } public virtual DateTime CreateDate { get; set; } public virtual int Version { get; set; } } }
Id:使用int值作为id;
IsDelete:是否删除;
CreateDate:创建时间;
Version:NHibernate中作并发控制;
(2)建立实体User
View Code
namespace Blog.Model.Entities { public class User:EntityBase { public virtual int Id{ get;set; } public virtual string UserName{ get;set; } public virtual string Password{ get;set; } public virtual string NickName{ get;set; } public virtual bool Gender{ get;set; } public virtual DateTime Birthday{ get;set; } public virtual string Email{ get;set; } public virtual string Address{ get;set; } public virtual string Phone{ get;set; } public virtual string QQ{ get;set; } public virtual bool IsActive{ get;set; } } }
注意:属性都加上virtual关键字
(3)建立实体xml映射文件
View Code
<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Blog.Model" assembly="Blog.Model"> <class name="Blog.Model.Entities.User, Blog.Model" table="`User`"> <id name="Id" type="Int32" unsaved-value="null"> <column name="UserId" length="4" sql-type="int" not-null="true" unique="true" index="PK_USER"/> <generator class="native" /> </id> <version name="Version" column="Version" type="integer" unsaved-value="0"/> <property name="UserName" type="String"> <column name="UserName" length="50" sql-type="nvarchar" not-null="false"/> </property> <property name="Password" type="String"> <column name="Password" length="50" sql-type="nvarchar" not-null="false"/> </property> <property name="NickName" type="String"> <column name="NickName" length="50" sql-type="nvarchar" not-null="false"/> </property> <property name="Gender" type="Boolean"> <column name="Gender" length="1" sql-type="bit" not-null="false"/> </property> <property name="Birthday" type="DateTime"> <column name="Birthday" length="8" sql-type="datetime" not-null="false"/> </property> <property name="Email" type="String"> <column name="Email" length="50" sql-type="varchar" not-null="false"/> </property> <property name="Address" type="String"> <column name="Address" length="50" sql-type="nvarchar" not-null="false"/> </property> <property name="Phone" type="String"> <column name="Phone" length="15" sql-type="varchar" not-null="false"/> </property> <property name="QQ" type="String"> <column name="QQ" length="10" sql-type="varchar" not-null="false"/> </property> <property name="IsActive" type="Boolean"> <column name="IsActive" length="1" sql-type="bit" not-null="false"/> </property> <property name="CreateDate" type="DateTime"> <column name="CreateDate" length="8" sql-type="datetime" not-null="false"/> </property> <property name="IsDelete" type="Boolean"> <column name="IsDelete" length="1" sql-type="bit" not-null="false"/> </class> </hibernate-mapping>
注意:hbmXML映射文件,属性必须设置为"嵌入的资源";XML中的Version字段必须在Id字段之后
NHibernate Id生成方式选择
映射文件id生成选择:<generator class="native" />
Assigned : 主键由外部程序负责生成,无需Hibernate参与,如Guid
identity : 采用数据库提供的主键生成机制
native : 由Hibernate根据底层数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式。
native : 由Hibernate根据底层数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式。
我上面只是列举了常用的几种,具体可以自己查找;
我们实体层的工作基本已经完成
二.建立NHibernate配置文件
我们使用的是单个的配置文件方式,配置文件名hibernate.cfg.xml;
View Code
<?xml version="1.0" encoding="utf-8" ?> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" > <session-factory name="NHibernateWeb"> <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property> <property name="connection.connection_string"> Data Source=.\SQLEXPRESS;Initial Catalog=BlogDB;Integrated Security=True;Pooling=False </property> <property name="adonet.batch_size">10</property> <property name="show_sql">true</property> <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property> <property name="command_timeout">10</property> <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property> <mapping assembly="Blog.Model"/> </session-factory> </hibernate-configuration>
三.建立Blog.Repository:数据访问层
(1)新建接口IRepository
View Code
namespace Blog.Repository { public interface IRepository<T, TId> where T : EntityBase { T Load(TId id); T Get(TId id); IList<T> GetAll(); IList<T> FindForPage(int index, int count); IList<T> Find(Expression<Func<T, bool>> query); T FindForSingle(Expression<Func<T, bool>> query); IList<T> HQLQuery(string query); TId Save(T entity); void SaveOrUpdate(T entity); void Update(T entity); void Delete(T t); void PhysicsDelete(TId id); } }
(2)新建Repository基类
View Code
namespace Blog.Repository { public abstract class Repository<T, TId> where T : EntityBase { private IUnitOfWork _uow; public Repository(IUnitOfWork uow) { _uow = uow; } protected virtual ISession Session { get { return NHSessionFactory.CreateSession(); } } /// <summary> /// 根据Id延迟加载获取实体 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual T Load(TId id) { return Session.Load<T>(id); } /// <summary> /// 根据Id获取实体 /// </summary> /// <param name="id"></param> /// <returns></returns> public virtual T Get(TId id) { return Session.Get<T>(id); } /// <summary> /// 获取所有实体 /// </summary> /// <returns></returns> public virtual IList<T> GetAll() { return Session.CreateCriteria(typeof(T)).List<T>();//使用Criteria //return Session.Query<T>().ToList(); //return Session.QueryOver<T>().List();//使用QueryOver linq } /// <summary> /// 获取分页数据 /// </summary> /// <param name="index">index=(pageNum-1)*pageCount</param> /// <param name="count">每页的条数pageCount</param> /// <returns></returns> public IList<T> FindForPage(int index, int count) { return Session.CreateCriteria(typeof(T)).SetMaxResults(count).SetFirstResult(index).List<T>(); } /// <summary> /// lambda表达式获取 /// </summary> /// <param name="query"></param> /// <returns></returns> public IList<T> Find(Expression<Func<T, bool>> query) { return Session.QueryOver<T>().Where(query).List(); } /// <summary> /// lambda表达式获取单个实体 /// </summary> /// <param name="query"></param> /// <returns></returns> public T FindForSingle(Expression<Func<T, bool>> query) { return Session.Query<T>().SingleOrDefault(query); } /// <summary> /// HQL查询 /// </summary> /// <param name="query"></param> /// <returns></returns> public IList<T> HQLQuery(string query) { return Session.CreateQuery(query).List<T>(); } /// <summary> /// 保存 /// </summary> /// <param name="entity"></param> /// <returns></returns> public virtual TId Save(T entity) { return (TId)Session.Save(entity); } /// <summary> /// 保存或更新 /// </summary> /// <param name="entity"></param> public virtual void SaveOrUpdate(T entity) { Session.SaveOrUpdate(entity); } /// <summary> /// 更新 /// </summary> /// <param name="entity"></param> public virtual void Update(T entity) { Session.Update(entity); } /// <summary> /// 删除 /// </summary> /// <param name="id"></param> public virtual void PhysicsDelete(TId id) { var entity = Get(id); Session.Delete(entity); } public void Delete(T t) { t.IsDelete = true; Update(t); } } }
(3)建立对应的实体的数据访问接口IUserRepository,该接口实现了IRepository
View Code
namespace Blog.Repository { public interface IUserRepository:IRepository<User,int> { } }
(4)建立实体的数据访问实现体
View Code
namespace Blog.Repository { public class UserRepository:Repository<User,int>,IUserRepository { public UserRepository(IUnitOfWork uow) : base(uow) {} } }
(5)Unit of Work模式,从上面的Repository基类可以看到,我们已经注入了该模式的实现;
1.建立IUnitOfWork接口
namespace Blog.Repository { public interface IUnitOfWork { void Commit(); } }
2.建立NHUnitOfWork类,实现IUnitOfWork接口
View Code
namespace Blog.Repository { public class NHUnitOfWork : IUnitOfWork { public ISession session { get { return NHSessionFactory.CreateSession(); } } public void Commit() { using (ITransaction transaction = session.BeginTransaction()) { try { session.Flush(); transaction.Commit(); } catch (Exception ex) { transaction.Rollback(); throw; } } } } }
(6)NHibernate的Session管理与初始化
为了合理控制Session的生命周期,在.netMVC中我们把Session的生命周期绑定在一次Action里;
1.建立接口ISessionStorage;
View Code
namespace Blog.Repository.SessionStorage { public interface ISessionStorage { ISession Get(); void Set(ISession value); } }
2.新建一个类HttpSessionStorage实现接口ISessionStorage;
public class HttpSessionStorage:ISessionStorage { private string sessionKey = "NhbSession"; public NHibernate.ISession Get() { ISession session = null; if (HttpContext.Current.Items.Contains(sessionKey)) session = (ISession)HttpContext.Current.Items[sessionKey]; return session; } public void Set(ISession value) { if (value != null) { if (HttpContext.Current != null) { HttpContext.Current.Items.Add(sessionKey, value); } } } }
3.新建一个工厂类,获取NHibernate的session
View Code
namespace Blog.Repository.SessionStorage { public static class NHSessionFactory { private static object locker = new object(); private static Configuration _configuration = null; private static ISessionFactory _sessionFactory = null; private static ISessionStorage SessionStorage{get;set;} public static void InitSessionFactory(ISessionStorage sessionStorage) { SessionStorage = sessionStorage;//使用ioc容器注入 } private static void CreateConfiguration() { _configuration = new Configuration().Configure(); } public static Configuration Configuration { get { lock (locker) { if (_configuration == null) { CreateConfiguration(); } return _configuration; } } set { _configuration = value; } } internal static ISessionFactory SessionFactory { get { if (_sessionFactory == null) { if (Configuration == null) { CreateConfiguration(); } lock (locker) { _sessionFactory = Configuration.BuildSessionFactory(); } } return _sessionFactory; } } public static ISession CreateSession() { ISession s = SessionStorage.Get(); if (s == null) { s = SessionFactory.OpenSession(); SessionStorage.Set(s); } return s; } } }
注意要在 void Application_Start()进行初始化
如下代码
NHSessionFactory.InitSessionFactory(container.Resolve<ISessionStorage>());//NHibernate session
这样我们的数据库访问层基本完成了!!