上次写了《多层架构通用查询的思考》,看了一下阅读量,还算满意,唯一不足的是评论太少了,支持或是反对,只要不进行人生攻击,我都还是乐意听的!是不是大部份朋友还没用.net framework3.0啊?真希望读过的朋友多给些中肯的评论,分析一下设计上的缺陷,让偶也进步一小点。
这次我还是分享一下我写的数据层吧!我在以前做的一个项目中,采用了ORM.现在不用了,原因很简单,ORM的架构很复杂,像我呆的小公司很少有同事认真看过我写的ORM框架,主要原因是没一个系统的规化,由于前期对很多问题没有考虑到,后来觉得对ORM改近很难;然后是他们熟悉了二层架构,觉得写SQL语句方便,DataTable用起来顺手。其实对于一个软件系统来说,采用什么技术都不是很重要,关键是架构的合理性,能否让软件质量得到改善、开发效率得到提升才是本质所在吧!说实话,对ORM的设计有点惭愧,大部份是根据NBear抄袭来的,直至今天的数据层访问类,还采用了NBear.Data设计思想,NBear里的DbHelper在数据层的封装与SqlHelper类是两个完全不同的境界。更是NBear的开源让我掌握了更多的.net新技术和面向对象的设计思想。下面谈一下我在数据层的设计思想,主要是在实现类中设计一个ActionType类型的RowAction字段,ActionType是一个枚举类型,主要对应Insert,Update,Delete,None操作,数据库并发处理是设置一个varchar类型的字段,通过存储Guid值来作为行版本信息。下面是数据层业务实体的代码。


public class DataProvider : GR.Data.DataProvider
{
#region TBEntity -- DataProvider
public virtual int TBEntityInsertOrUpdate(TBEntity entity, DbTransaction tran)
{
string _RowVersion = Guid.NewGuid().ToString();
int iEffectedRow = 0;
string tableName = "TBEntity";
string[] Cols = new string[] {"EntityGroupID","Name","HeaderText","ClazzName","TableName","Description","Version","SysAttr"};
object[] values = new object[] {entity.EntityGroupID,entity.Name,entity.HeaderText,entity.ClazzName,entity.TableName,entity.Description,entity.Version,entity.SysAttr};
string where = string.Empty;
try{
switch(entity.RowAction){
case ActionType.Insert:
iEffectedRow = Gateway.Default.Insert(tableName, Cols, values);
entity.ID = int.Parse(Gateway.Default.DbHelper.ExecuteScalar(string.Format(Gateway.Default.Db.DbProvider.SelectLastInsertedRowAutoIDStatement,tableName)).ToString());
entity.RowVersion = _RowVersion;
return iEffectedRow;
case ActionType.Update:
where = BuildEqualWhereStr(new string[] { "ID","RowVersion._RowVersion" });
iEffectedRow = Gateway.Default.Update(tableName, Cols, values, where, new object[] {entity.ID,entity.RowVersion });
entity.RowVersion = _RowVersion;
return iEffectedRow;
case ActionType.Delete:
where = BuildEqualWhereStr(new string[] { "ID","RowVersion._RowVersion" });
return Gateway.Default.Delete(tableName, where, new object[] {entity.ID,entity.RowVersion });
}
}
catch (Exception ex){
throw ex;
}
return 0;
}
public virtual List<TBEntity> TBEntities()
{
return TBEntities(string.Empty);
}
public virtual List<TBEntity> TBEntities(string query)
{
return TBEntities(query,null);
}
public virtual List<TBEntity> TBEntities(string query,object[] paramValues)
{
List<TBEntity> values = new List<TBEntity>();
string tableName = "TBEntity";
using (IDataReader dr = Gateway.Default.Select(tableName,query, paramValues))
{
while (dr.Read())
values.Add(PopulateTBEntity(dr) as TBEntity);
}
AssignEntitySetForTBEntity(values);
return values;
}
protected object PopulateTBEntity(IDataReader dr)
{
TBEntity entity = new TBEntity();
if (!Convert.IsDBNull(dr["ID"])) entity.ID = Convert.ToInt32(dr["ID"]); //编号
if (!Convert.IsDBNull(dr["EntityGroupID"])) entity.EntityGroupID = Convert.ToInt32(dr["EntityGroupID"]); //实体组
if (!Convert.IsDBNull(dr["Name"])) entity.Name = Convert.ToString(dr["Name"]); //名称
if (!Convert.IsDBNull(dr["HeaderText"])) entity.HeaderText = Convert.ToString(dr["HeaderText"]); //标题
if (!Convert.IsDBNull(dr["ClazzName"])) entity.ClazzName = Convert.ToString(dr["ClazzName"]); //类名
if (!Convert.IsDBNull(dr["TableName"])) entity.TableName = Convert.ToString(dr["TableName"]); //表名
if (!Convert.IsDBNull(dr["Description"])) entity.Description = Convert.ToString(dr["Description"]); //描述
if (!Convert.IsDBNull(dr["Version"])) entity.Version = Convert.ToString(dr["Version"]); //版本号
if (!Convert.IsDBNull(dr["SysAttr"])) entity.SysAttr = Convert.ToBoolean(dr["SysAttr"]); //系统属性
if (!Convert.IsDBNull(dr["RowVersion"])) entity.RowVersion = Convert.ToString(dr["RowVersion"]); //行版本
return entity;
}
protected void AssignEntitySetForTBEntity(List<TBEntity> values)
{
List<TBEntityGroup> _EntityGroup = TBEntityGroups();
List<TBEntity_R_Properties> _TBEntity_R_Properties = TBEntity_R_Properties();
foreach (TBEntity entity in values)
{
entity.EntityGroup = _EntityGroup.SingleOrDefault(p => p.ID == entity.EntityGroupID);
entity.TBEntity_R_Properties.Assign(_TBEntity_R_Properties.Where(p => p.EntityId == entity.ID),true);
}
}
#endregion
}
代码补充说明
1、entity.ID = int.Parse(Gateway.Default.DbHelper.ExecuteScalar(string.Format(Gateway.Default.Db.DbProvider.SelectLastInsertedRowAutoIDStatement, tableName)).ToString());
主要实现新增后回写自动增量字段值
2、entity.TBEntity_R_Properties.Assign(_TBEntity_R_Properties.Where(p => p.EntityId == entity.ID), true);
TBEntity_R_Properties是一个自定义EntitySet类型的字段,通常表示1:n的关系。Assign(..,true),是赋值数据,并将当前数据设为原始状态(None)
对于数据层来说,其实所有的映射关系都可以通过代码自动生成工具来生成,听说Codesmith能模板生成相应的代码,不过我没仔细去研究过,自已写了一个傻瓜的代码生成工具。最后,非常感谢NBear团队的开源,同时也希望园子里的其它兄弟也把没有涉及公司机密的好东东拿出来共享一下,共同学习!