博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
步步为营:Asp.net 通用数据容器的缺陷
阅读量:6870 次
发布时间:2019-06-26

本文共 9750 字,大约阅读时间需要 32 分钟。

在做试客项目中,我们项目使用的数据框架是ADO.Net, 我常常在想是不是有很好的办法能通用业务到数据请求。即使不能做到所有的业务,但对于同一种业务能达到通用也好。

于是我就想用泛型尝试解决这个问题,用分页来讲解。

 在控制器我这样写

List
lstAchievements = BLLAchievements.GetAchievementsByWhereHD(item);

BLL我这样写

#region 业绩存储过程分页 ///  /// 业绩存储过程分页 ///  ///  /// 
public static List
GetAchievementsByWhere(PagerEntity item) {
List
list = DatabaseProvider.GetInstance().GetCommonPager
(item); return list; } #endregion

DAL我这样写

#region 通用存储过程分页 ///  /// 通用存储过程分页 ///  /// 
/// ///
public List
GetCommonPager
(PagerEntity item) where T : class, new() {
//创建返回的集合 List
objlist = new List
(); string strsql = string.Empty; //创建属性的集合 List
prlist = new List
(); //获得反射的入口 Type t = typeof(T); //获取所有公共属性 PropertyInfo[] ps = t.GetProperties(); strsql = "P_CommonPager_RowNomber"; DbParameter[] param = { SQLHelper.MakeParam("@tblName",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,item.TblName), SQLHelper.MakeParam("@strGetFields",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,item.StrGetFields), SQLHelper.MakeParam("@strOrder",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,item.StrOrder), SQLHelper.MakeParam("@strWhere",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,item.StrWhere), SQLHelper.MakeParam("@pageIndex",(DbType)SqlDbType.Int,4, ParameterDirection.Input,item.PageIndex), SQLHelper.MakeParam("@pageSize",(DbType)SqlDbType.Int,4, ParameterDirection.Input,item.PageSize), SQLHelper.MakeParam("@recordCount",(DbType)SqlDbType.Int,4, ParameterDirection.Output,item.RecordCount), SQLHelper.MakeParam("@doCount",(DbType)SqlDbType.Int,4, ParameterDirection.Input,item.DoCount), }; param[6].Direction = ParameterDirection.Output; using (IDataReader rs = SQLHelper.ExecuteReader(CommandType.StoredProcedure, strsql, param)) { while (rs.Read()) { //新实例泛型 T obj = new T(); //遍历属性数组 foreach (PropertyInfo p in ps) { //将对应的属性填充给对象 p.SetValue(obj, rs[p.Name] ?? 0, null); } //添加对象到返回集合 objlist.Add(obj); } } item.RecordCount = TypeConverter.ObjectToInt(param[6].Value); return objlist; } #endregion

因为DataReader需要关闭后才能取返回值,所以我将反射属性写到了数据层,实现这功能。

但是这样产生了一个问题BLL不能通用,这是我非常懊恼的问题。

之后我又修整了代码,可能是我自己纠结的问题因为就只是分页过程有返回值,其他倒不需要
于是我又写了一遍

在控制器这样写

List
LstTryList = Users.DataTableToList
(Users.GetCommonPager(tblName, strGetFields, pkName, strOrder, strWhere, pageIndex, pageSize, ref recordCount, doCount, EnumCollection.Enum_SpCommon.SPROWNUMBER));

BLL中

#region 通用存储过程分页 ///  /// 通用存储过程分页 ///  /// 表名或者视图名如:'sk_Users' /// 需要返回的列如:'uid,username' /// 主键 /// 排序的字段名如:'order by id desc' /// 查询条件(注意:不要加where)如:'username like ''%222name%'''  /// 页码如:2 /// 每页记录数如:20 /// out 记录总数 /// 非0则统计,为0则不统计(统计会影响效率) /// 枚举:选择通用过程 /// 
DataTable
public static DataTable GetCommonPager(string tblName, string strGetFields, string pkName, string strOrder, string strWhere, int pageIndex, int pageSize, ref int recordCount, int doCount, EnumCollection.Enum_SpCommon SpCommon) {
DataSet ds = DatabaseProvider.GetInstance(). GetCommonPager(tblName, strGetFields, pkName, strOrder, strWhere, pageIndex, pageSize, ref recordCount, doCount, SpCommon); DataTable table = ds.Tables[0]; return table; } #endregion

DAL中

#region 通用存储过程分页 ///  /// Author:梁雄开 /// CreatDate:2010.04.23 /// Description:通用存储过程分页 ///  /// 表名如:'sk_Users' /// 需要返回的列如:'uid,username' /// 主键 /// 排序的字段名如:'order by id desc' /// 查询条件(注意:不要加where)如:'username like ''%222name%'''  /// 页码如:2 /// 每页记录数如:20 /// out 记录总数 /// 非0则统计,为0则不统计(统计会影响效率) /// 枚举:选择通用过程 /// 
public DataSet GetCommonPager(string tblName, string strGetFields, string pkName, string strOrder, string strWhere, int pageIndex, int pageSize, ref int recordCount, int doCount, EnumCollection.Enum_SpCommon SpCommon) {
DataSet ds = new DataSet(); string strsql = string.Empty; if (SpCommon == EnumCollection.Enum_SpCommon.SPNOTINT) {
strsql = "P_CommonPager_NotIn"; DbParameter[] param = {
SqlHelper.MakeParam("@tblName",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,tblName), SqlHelper.MakeParam("@strGetFields",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,strGetFields), SqlHelper.MakeParam("@pkName",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,pkName), SqlHelper.MakeParam("@strOrder",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,strOrder), SqlHelper.MakeParam("@strWhere",(DbType)SqlDbType.VarChar,8000, ParameterDirection.Input,strWhere), SqlHelper.MakeParam("@pageIndex",(DbType)SqlDbType.Int,4, ParameterDirection.Input,pageIndex), SqlHelper.MakeParam("@pageSize",(DbType)SqlDbType.Int,4, ParameterDirection.Input,pageSize), SqlHelper.MakeParam("@recordCount",(DbType)SqlDbType.Int,4, ParameterDirection.Output,recordCount), SqlHelper.MakeParam("@doCount",(DbType)SqlDbType.Int,4, ParameterDirection.Input,doCount), }; param[7].Direction = ParameterDirection.Output; ds = SqlHelper.ExecuteDataset(CommandType.StoredProcedure, strsql, param); recordCount = TypeConverter.ObjectToInt(param[7].Value); } if (SpCommon == EnumCollection.Enum_SpCommon.SPROWNUMBER) {
strsql = "P_CommonPager_RowNomber"; DbParameter[] param = {
SqlHelper.MakeParam("@tblName",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,tblName), SqlHelper.MakeParam("@strGetFields",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,strGetFields), SqlHelper.MakeParam("@strOrder",(DbType)SqlDbType.VarChar,255, ParameterDirection.Input,strOrder), SqlHelper.MakeParam("@strWhere",(DbType)SqlDbType.VarChar,8000, ParameterDirection.Input,strWhere), SqlHelper.MakeParam("@pageIndex",(DbType)SqlDbType.Int,4, ParameterDirection.Input,pageIndex), SqlHelper.MakeParam("@pageSize",(DbType)SqlDbType.Int,4, ParameterDirection.Input,pageSize), SqlHelper.MakeParam("@recordCount",(DbType)SqlDbType.Int,4, ParameterDirection.Output,recordCount), SqlHelper.MakeParam("@doCount",(DbType)SqlDbType.Int,4, ParameterDirection.Input,doCount), }; param[6].Direction = ParameterDirection.Output; ds = SqlHelper.ExecuteDataset(CommandType.StoredProcedure, strsql, param); recordCount = TypeConverter.ObjectToInt(param[6].Value); } return ds; } #endregion

这次换成DataSet获取数据,出来后在转换反射出想要的列表。

#region DataTable转List ///  /// DataTable转List ///  /// 
泛型
/// 数据表格 ///
public static List
DataTableToList
(DataTable dt) where T : class,new() {
//创建一个属性的列表 List
prlist = new List
(); //获取T的类型实例 反射的入口 Type t = typeof(T); //获得T 的所有的Public 属性 并找出T属性和DataTable的列名称相同的属性(PropertyInfo) 并加入到属性列表 Array.ForEach
(t.GetProperties(), p => { if (dt.Columns.IndexOf(p.Name) != -1) prlist.Add(p); }); //创建返回的集合 List
oblist = new List
(); foreach (DataRow row in dt.Rows) { //创建T的实例 T obj = new T(); //找到对应的数据 并赋值 prlist.ForEach(p => { if (row[p.Name] != DBNull.Value) p.SetValue(obj, row[p.Name], null); }); //放入到返回的集合中. oblist.Add(obj); } return oblist; } #endregion

完成自己想要的List,但是使用DataSet性能不好。转换也花费了一层消耗,还是不够完美。

让我们再次整理次吧。

先让我们讨论看看问题:

强耦合

 

DataReader和DataTable不允许你透明地检索数据,而不影响用户界面的代码。这意味这你的应用程序和数据库结构是强耦合的,对数据库结构的任何改变都需要对你的程序有所改动。这应该是在数据访问层解决的问题,而不是在用户界面层。

 

很多时候,数据库都是为一个应用程序提供服务,这样数据组织起来很容易被使用。但是,有些程序是建立在已有的数据库之上的,这时候就不能对数据库做任何改动,因为还有其他程序在使用这个数据库。这种情况下,你的代码可能跟数据库耦合性更强,甚至超出你的想象。例如,订单可能存储在一个表中,送货地址存储在另一个表中。数据访问层的代码可能减少这种影响,但是问题依然存在。

 

当列的名称发生改变又会发生什么呢,其实在开发的过程中这种事情经常发生。结果是,你必须改变用户界面层的代码来适应这一变化。

你会这样写

object shippingAddress = orders.Rows[0]["ShippingAddress"];

你获取列需要自己写列名,也就是说当修改数据结构,你就必须维护这里。

string shippingAddress = (string)orders.Rows[0]["ShippingAddress"]; string shippingAddress = orders.Rows[0]["ShippingAddress"].ToString();

除了这些,你还需要对类型进行显示的转换,进行类型转换在性能和内存使用上都有一定的损失,因为从值类型转换到引用类型要进行装箱操作,反之进行拆箱操作。

DataReader比DataTable有优势,它提供了不需要显式转换访问字段的类型方法,方法的参数接受列在一行中得索引值。它还提供了一个提供列的名称返回索引的方法。但是输入的字符串错误,也会抛出异常。

string address = rd.GetString(rd.GetOrdinal("ShippingAddress")); string address = rd.GetString(rd.GetOrdinal("ShipingAdres")); //exception

性能问题

 

DataSet可能是.NET类库中最复杂的结构了。它包括一个或多个DataTable实例,每个DataTable实例又包括一系列DataRow对象,每个DataRow对象又由DataColumn对象构成的。DataTable可以由一个或多个列组成组成一个主键,还可以在某些列上声明外键,列还支持版本控制等等。尽管这些特性很多时候都是没用的,也常常被开发人员忽略,但是DataSet仍然在内部创建包含这些对象的空的集合。这对一个独立的应用程序可能是微不足道的性能损失,但是在一个多用户的环境中,有成千上万条请求,这将是不可接受的。

 

相比之下,DataReader可以适用在不同的场景中。DataTable从数据库中读出所有的数据放到内存中,但是很多时候你并不需要这么多的数据在内存中,你只需要一条条的从数据库中读出记录即可。另外一种情况,你经常查询数据而不用更新它,这种情况下,DataReader是最佳选择,因为它使用只读的方式检索数据。尽管DataReader提升了性能,但是它依然有类型转换带来的性能损失。

 

 

 

 

转载于:https://www.cnblogs.com/79039535/archive/2011/12/19/2293705.html

你可能感兴趣的文章
华为宣布开源流处理平台查询语言 StreamCQL
查看>>
2016 年 6 月 RedMonk 编程语言排行榜
查看>>
《Adobe Photoshop CC经典教程(彩色版)》—第1课1.4节在Photoshop中还原操作
查看>>
HttpClient使用详解
查看>>
增强现实?先不要指望那些眼镜了
查看>>
《iOS 6核心开发手册(第4版)》——1.10节秘诀:使用多触摸交互
查看>>
《云数据管理:挑战与机遇》一第1章
查看>>
《嵌入式C编程实战》——1.5 软件开发工具
查看>>
分析3000份技术面试数据:这几大指标比你毕业于哪所学校更要紧
查看>>
Linux有问必答:如何检查PDF中使用了哪种字体
查看>>
《Lua游戏AI开发指南》一2.1 新建一个沙箱项目
查看>>
如何使用 Weave 以及 Docker 搭建 Nginx 反向代理/负载均衡服务器
查看>>
《Android 应用测试指南》——第1章,第1.4节测试的种类
查看>>
对jquery val 获取input 文本框值进行扩展
查看>>
MySQL (select_paren) union_order_or_limit 行为
查看>>
并发不是并行,它更好!
查看>>
nltk 自己训练模型例子
查看>>
间谍卫星的基础?YOLT——利用卷积神经网络对卫星影像进行多尺度目标检测(Part I)...
查看>>
jstl_开发第一个标签
查看>>
程序员哇,你想在下个情人节或者520脱单么?这个秘籍不能错过
查看>>