接上篇,完成NHibernate的Session管理和初始化之后,现在可以完成我们的数据库访问基类RepositoryNhbImpl了
- RepositoryNhbImpl数据库访问基类代码:
代码注意: return SessionBuilder.CreateSession(); 这里通过我们上篇写的SessionBuilder去创建Session,具体实现其实就是简单的把NHibernate的方法封装了一下。namespace Demo.HIS.FrameWork.Repository.Nhb
{
public class RepositoryNhbImpl < T > : IRepository < T > where T : Entity
{
protected virtual ISession Session
{
get { return SessionBuilder.CreateSession(); }
}
#region IRepository<T> 成员
public virtual T Load( string id)
{
try
{
T reslut = Session.Load < T > (id);
if (reslut == null )
throw new RepositoryException( " 返回实体为空 " );
else
return reslut;
}
catch (Exception ex)
{
throw new RepositoryException( " 获取实体失败 " , ex);
}
}
public virtual T Get( string id)
{
try
{
T reslut = Session.Get < T > (id);
if (reslut == null )
throw new RepositoryException( " 返回实体为空 " );
else
return reslut;
}
catch (Exception ex)
{
throw new RepositoryException( " 获取实体失败 " , ex);
}
}
public virtual IList < T > GetAll()
{
return Session.CreateCriteria < T > ()
.AddOrder(Order.Asc( " CreateTime " ))
.List < T > ();
}
public virtual void SaveOrUpdate(T entity)
{
try
{
Session.SaveOrUpdate(entity);
Session.Flush();
}
catch (Exception ex)
{
throw new RepositoryException( " 插入实体失败 " , ex);
}
}
public virtual void Update(T entity)
{
try
{
Session.Update(entity);
Session.Flush();
}
catch (Exception ex)
{
throw new RepositoryException( " 更新实体失败 " , ex);
}
}
public virtual void PhysicsDelete( string id)
{
try
{
var entity = Get(id);
Session.Delete(entity);
Session.Flush();
}
catch (System.Exception ex)
{
throw new RepositoryException( " 物理删除实体失败 " , ex);
}
}
public virtual void Delete( string id)
{
try
{
var entity = Get(id);
entity.IsDelete = true ;
Update(entity);
}
catch (System.Exception ex)
{
throw new RepositoryException( " 删除实体失败 " , ex);
}
}
#endregion
}
} - 一般在信息管理系统中我们都会做“字典管理”功能,以方便客户自己维护一些下拉选项,如下图所示:
- 根据上面的需求,我们需要创建两个业务对象:
字典类别DicCategory,虽然上图中被我搞花了,但你依然可以看出他是一个树形结构:) 而且可以预见在我们的系统中将来肯定有不少类似的树形结构,所以我们建立一个表示树形结构的基类:
代码namespace Demo.HIS.FrameWork.DomainBase
{
/// <summary>
/// 树型结构节点实体
/// </summary>
public abstract class TreeNode:Entity
{
/// <summary>
/// 名称
/// </summary>
public virtual string Name { get ; set ; }
/// <summary>
/// 标识树形结构的编码
/// </summary>
public virtual string TreeCode { get ; set ; }
/// <summary>
/// 是否叶节点
/// </summary>
public virtual bool Leaf { get ; set ; }
/// <summary>
/// 父节点Id
/// </summary>
public virtual string ParentId { get ; set ; }
/// <summary>
/// 节点深度
/// </summary>
public virtual int Level { get ; set ; }
}
}注:在这个类里我们可以内聚一些树形结构的逻辑(与数据库访问无关),比如生产树节点编码的算法之类的,这里我就不写了
字典类别DicCategory继承TreeNode:代码/// <summary>
/// 字典类别
/// </summary>
public class DicCategory : TreeNode
{
public override string TreeCode
{
get
{
return base .TreeCode;
}
set
{
if (String.IsNullOrEmpty(value))
throw new NotNullException();
base .TreeCode = value;
}
}
public override string Name
{
get
{
return base .Name;
}
set
{
if (String.IsNullOrEmpty(value))
throw new NotNullException();
base .Name = value;
}
}
/// <summary>
/// 包含的字典
/// </summary>
public virtual ISet < Dictionary > Dics { get ; set ; }
/// <summary>
/// 描述
/// </summary>
public virtual string Description { get ; set ; }
/// <summary>
/// 节点深度
/// </summary>
public override int Level
{
get
{
return base .Level;
}
set
{
if ( base .Level > 2 )
throw new ValidationException( " 约定此业务对象的节点深度不超过2 " );
base .Level = value;
}
}
}可以看到我重写了基类的一些属性,使名称和编码不能为空,节点深度不能超过2级
注意一下 这个属性 public virtual ISet<Dictionary> Dics { get; set; } 表示一个字典类别里包含了多个字典项(字典的类我们接着就建...),ISet<T>表示不重复的集合,实在整不明白你也可以理解成IList<T>。
字典项Dictionary:代码/// <summary>
/// 字典
/// </summary>
public class Dictionary : InputItem
{
/// <summary>
/// 排序
/// </summary>
public virtual int Index { get ; set ; }
/// <summary>
/// 字典类别
/// </summary>
public virtual DicCategory Category { get ; set ; }
/// <summary>
/// 描述
/// </summary>
public virtual string Description { get ; set ; }
}父类InputItem我们已经在Asp.Net大型项目实践(3)-业务领域对象建模的例子中讲过了,注意理解属性public virtual DicCategory Category { get; set; }
-
建立数据库表:
可以看到表间关系是典型的一对多
注:这里先给个数据建模工具PowerDesigner 12 的截图,后面会给出PD12的文件(PD支持导出数据库表,这里我是按Oracel10g建的物理模型) -
建立NHibernate的Xml映射文件来映射对象与数据库表之间的关系
注1:下载的NHibernate里含有两个.xsd文件,把他们放在X:\Program Files\Microsoft Visual Studio 9.0\Xml\Schemas目录里可实现智能提醒
注2:你也可以CodeSmith这类的代码生成工具去生成你的Xml映射文件
注3:如果你不喜欢用Xml映射,NHibernate也支持Attribute;
注4:注意Xml映射文件的生成操作为嵌入资源
字典类别DicCategory的Xml:代码<? xml version="1.0" encoding="utf-8" ?>
< hibernate-mapping xmlns ="urn:nhibernate-mapping-2.2"
assembly ="Infrastructure.Core" namespace ="Demo.HIS.Infrastructure.Core" >
< class name ="Demo.HIS.Infrastructure.Core.DicCategory" table ="INFRA_DICCATEGORY" dynamic-insert ="true" dynamic-update ="true" where ="IsDelete=0" >
< id name ="Id" column ="DICCATEGORY_ID" type ="String" >
< generator class ="assigned" />
</ id >
< version name ="Version" column ="VERSION" unsaved-value ="0" />
< property name ="Name" column ="NAME" type ="String" />
< property name ="ParentId" column ="PARENT_ID" type ="String" />
< property name ="TreeCode" column ="TREE_CODE" type ="String" />
< property name ="Leaf" column ="LEAF" type ="Boolean" />
< property name ="Description" column ="DESCRIPTION" type ="String" />
< property name ="CreateTime" column ="CREATETIME" type ="DateTime" />
< property name ="IsDelete" column ="ISDELETE" type ="Boolean" />
< property name ="Level" column ="NODE_LEVEL" type ="Int32" />
< set name ="Dics" table ="INFRA_DICTIONARY" generic ="true" lazy ="true" fetch ="subselect" where ="IsDelete=0" >
< key column ="DICCATEGORY_ID" />
< one-to-many class ="Demo.HIS.Infrastructure.Core.Dictionary" />
</ set >
</ class >
</ hibernate-mapping >字典项Dictionary的Xml:
代码<? xml version="1.0" encoding="utf-8" ?>
< hibernate-mapping xmlns ="urn:nhibernate-mapping-2.2"
assembly ="Infrastructure.Core" namespace ="Demo.HIS.Infrastructure.Core" >
< class name ="Demo.HIS.Infrastructure.Core.Dictionary" table ="INFRA_DICTIONARY" dynamic-insert ="true" dynamic-update ="true" where ="IsDelete=0" >
< id name ="Id" column ="DICTIONARY_ID" type ="String" >
< generator class ="assigned" />
</ id >
< version name ="Version" column ="VERSION" unsaved-value ="0" />
< property name ="Name" column ="NAME" type ="String" />
< property name ="Code" column ="CODE" type ="String" />
< property name ="InputCode1" column ="INPUT_CODE1" type ="String" />
< property name ="InputCode2" column ="INPUT_CODE2" type ="String" />
< property name ="InputCode3" column ="INPUT_CODE3" type ="String" />
< property name ="Index" column ="INDEX_FIELD" type ="Int32" />
< property name ="Description" column ="DESCRIPTION" type ="String" />
< property name ="CreateTime" column ="CREATETIME" type ="DateTime" />
< property name ="IsDelete" column ="ISDELETE" type ="Boolean" />
< many-to-one name ="Category" column ="DICCATEGORY_ID" not-null ="true" lazy ="proxy" class ="Demo.HIS.Infrastructure.Core.DicCategory" />
</ class >
</ hibernate-mapping >具体配置含义这里不详细解释,自己去Google....
-
建立字典类DicCategory和字典项Dictionary的数据访问接口及实现
接口:namespace Demo.HIS.Infrastructure.Core.Repositories
{
/// /字典类别的数据库访问接口
public interface IDicCategoryRepository : IRepository < DicCategory >
{
}
}namespace Demo.HIS.Infrastructure.Core.Repositories
{
// 字典项的数据库访问接口
public interface IDictionaryRepository : IRepository < Dictionary >
{
}
}实现:
namespace Demo.HIS.Infrastructure.Repositories
{
public class DicCategoryRepositoryImpl : RepositoryNhbImpl < DicCategory > ,IDicCategoryRepository
{
}
}
namespace Demo.HIS.Infrastructure.Repositories.Data
{
public class DictionaryRepositoryImpl : RepositoryNhbImpl < Dictionary > , IDictionaryRepository
{
}
}
到此我们就实现了NHibernate基本的数据库访问
源码: HISDemo-3.rar
PowerDesigner 12可以打开的数据库建模文件:PhysicalDataModel_1.rar