终于告别一大堆名字不一样的Dao了,统统删掉,这样能让配置文件buessineConfig.xml瘦下来不少,看着舒服。也许看官您会问:如果对于特定的实体要实现事务呢 ——确实,这个Dao只是把通用的部分提炼出来,如果是个性化的操作,还是要单独创建操作类的。比如事务,创建一个基于接口实现的类,加上Transaction元标记,最后,在配置文件中指派Spring.net的某个AOP Proxy对象,让它来帮助你实现事务(在此向以前读过在下糙文的读者致歉,在spring.net中,Transaction元标记只是标注事务的范围,而具体的实现是基于 接口 及 接口切面代理对象 共同完成的)
近一年时间没有写blog了,由于各种忙——是时候更新一下了。
重新审视了一翻以前写的东西,发现问题不少,以 .net企业级架构实战之5——基于接口的访问层实现 为例,就一般的访问层对象而言,功能大致相同,每一个都存在Save(),Update(),Delete(),LoadFromId(),SearchByWhere()等功能,在DaoTemplate模板类已经实现泛型化的基础上,如此实现各个Dao实在冗余啰嗦。
每个Dao最大的差异,在于这一片断:
private const string TableName = "TB_USER_MAIN"; //表名
private const string PrimaryKey = "Id"; //主键
它们被这样使用:
/**//// <summary>
/// 分页
/// </summary>
public DataTable GetPagerByStoreProc(string Columns,int pageSize, int pageIdx
, string OrderColumn, bool orderType, string condition)
{
return DaoTemplate.GetPageEntitesByStoredProc
(TableName, PrimaryKey, Columns, OrderColumn, pageSize, pageIdx, orderType, condition);
}
说白了,Dao除了名字不一样,最大差异体现在 对应实体数据源信息上。实体数据源信息的差异,应该由实体来描述,而不是Dao, "omg,多么糟糕的设计!"。
改过来,为实体创建一个描述数据源信息的属性类,以元标记的方式标注,其余的工作,一个泛型的Dao足矣。
- 描述数据源信息的TableInfoAttribute类:
TableInfoAttribute.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace woodigg.model
{
/// <summary>
/// 实体的TABLE属性
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class TableInfoAttribute : Attribute
{
#region Private Members
private string tableName;
private string primaryKey;
private string columns;
#endregion
#region Properties
/// <summary>
/// 表名
/// </summary>
/// <value>The table name.</value>
public string TableName
{
get { return tableName; }
set
{
tableName = value;
}
}
/// <summary>
/// 主键
/// </summary>
/// <value>The table primaryKey.</value>
public string PrimaryKey
{
get { return primaryKey; }
set
{
primaryKey = value;
}
}
/// <summary>
/// 所有列
/// </summary>
/// <value>The table columns.</value>
public string Columns
{
get { return columns; }
set
{
columns = value;
}
}
#endregion
}
}
- 设计这个泛型类Dao的接口,如IbandDaoSpring:
interface IbandDaoSpring
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace woodigg.DAO
{
public interface IbandDaoSpring
{
/// <summary>
/// 存
/// </summary>
bool Save<T>(T ab);
/// <summary>
/// 更新
/// </summary>
bool Update<T>(T ab);
/// <summary>
/// 删除
/// </summary>
bool Delete<T>(T ab);
/// <summary>
/// 读
/// </summary>
T LoadFromId<T>(int id);
/// <summary>
/// 查
/// </summary>
IList<T> SearchByWhere<T>(string where);
/// <summary>
/// 查排序
/// </summary>
IList<T> SearchByWhereOrder<T>(string where, string propertyName, bool ascending);
/// <summary>
/// 分页
/// 给出全部参数
/// </summary>
/// <param name="tableName">表名</param>
/// <param name="PrimaryKey">主键</param>
/// <param name="Columns">列</param>
/// <param name="pageSize">页大小</param>
/// <param name="pageIdx">页号</param>
/// <param name="OrderColumn">排序列</param>
/// <param name="orderType">true降序 false 升级</param>
/// <param name="condition">条件</param>
/// <returns>DataTable</returns>
DataTable GetPagerByStoreProc<T>(string tableName,string PrimaryKey,string Columns, int pageSize, int pageIdx
, string OrderColumn, bool orderType, string condition);
/// <summary>
/// 重载版本分页
/// 表名,主键 由元标记(TableInfo)给出
/// </summary>
DataTable GetPagerByStoreProc<T>(string Columns, int pageSize, int pageIdx
, string OrderColumn, bool orderType, string condition);
/// <summary>
/// 重载版本分页
/// 表名,主键,所有列 由元标记(TableInfo)给出
/// </summary>
DataTable GetPagerByStoreProc<T>(int pageSize, int pageIdx
, string OrderColumn, bool orderType, string condition);
/// <summary>
/// 获取记录数
/// </summary>
int GetRecordCount<T>(string where);
}
}
- 找个实体类,给它加上TableInfo数据源信息元标记:
TableInfo attribute on class
[TableInfo(TableName = "TB_MEDIAAlbumRecommand", PrimaryKey = "Id", Columns =
"Id,AlbumName,AlbumPhoto,AlbumIntro,Rating,Company,Artist,RecommandText,RegDate,Title,IsPublish,MemberId,AlbumGenre")]
public class MEDIAAlbumRecommand{}
* 找个页面,测试一下:
DataTable dt = BandDaoSpring.GetPagerByStoreProc<MEDIAAlbumRecommand>
(10, 1, "Id", false, "1=1");
找个页面,测试一下:
DataTable dt = BandDaoSpring.GetPagerByStoreProc<MEDIAAlbumRecommand>
(10, 1, "Id", false, "1=1");
终于告别一大堆名字不一样的Dao了,统统删掉,这样能让配置文件buessineConfig.xml瘦下来不少,看着舒服。也许看官您会问:如果对于特定的实体要实现事务呢 ——确实,这个Dao只是把通用的部分提炼出来,如果是个性化的操作,还是要单独创建操作类的。比如事务,创建一个基于接口实现的类,加上Transaction元标记,最后,在配置文件中指派Spring.net的某个AOP Proxy对象,让它来帮助你实现事务(在此向以前读过在下糙文的读者致歉,在spring.net中,Transaction元标记只是标注事务的范围,而具体的实现是基于 接口 及 接口切面代理对象 共同完成的)
- 来个小示例吧,先从配置文件说起,在applicationContext.xml配置了这样一个拦截器:
<!--事务拦截器-->
<object id="TransactionInterceptor" type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
<property name="TransactionManager" ref="HibernateTransactionManager" />
<property name="TransactionAttributeSource">
<object type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data" />
</property>
</object>
ImediaInterface
using System;
using System.Collections.Generic;
using System.Text;
using woodigg.model;
namespace woodigg.DAO
{
/// <summary>
/// 用于事务的接口
/// </summary>
public interface ImediaInterface
{
bool TransactionAdd(IList<MEDIARead> list);
}
}
ImediaInterface实现
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using Spring.Context;
using Spring.Context.Support;
using Spring.Dao;
using Spring.Data.NHibernate.Support;
using woodigg.model;
using Spring.Transaction.Interceptor;
namespace woodigg.DAO
{
public class MediaTransaction : ImediaInterface
{
#region 注入的DaoTemplate
private DaoTemplate _DaoTemplate;
public DaoTemplate DaoTemplate
{
get { return _DaoTemplate; }
set { _DaoTemplate = value; }
}
#endregion
[Transaction(ReadOnly=false)]
public bool TransactionAdd(IList<MEDIARead> list)
{
bool flag = true;
foreach (MEDIARead r in list)
{
if (!DaoTemplate.Save<MEDIARead>(r)) {
flag = false;
break;
}
}
return flag;
}
}
}
- 在配置文件中,声明这个MediaTransaction对象,同时使用 ObjectNameAutoProxyCreator 代理来负责为它植入事务监听:
<!--事务-->
<object id="MediaTransaction" type="woodigg.DAO.MediaTransaction,woodigg.DAO" autowire="byName" />
<object name="autoProxyCreator"
type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
<property name="InterceptorNames" value="TransactionInterceptor"/>
<property name="ObjectNames">
<list>
<idref local="MediaTransaction"/>
</list>
</property>
</object>
list中可以安放你需要植入事务拦截器的任何对象。
再次表示歉意!!