Asp.Net大型项目实践(4)-用NHibernate保存和查询我们的业务领域对象之实现基本的数据库访问(附源码)
接上篇,完成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