首页> 搜索结果页
"sqlserver 通用分页存储过程" 检索
共 59 条结果
SQLserver分页 高效率
SQL Server 存储过程的分页,这个问题已经讨论过几年了,很多朋友在问我,所以在此发表一下我的观点 建立表: CREATE TABLE [TestTable] ( [ID] [int] IDENTITY (1, 1) NOT NULL , [FirstName] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL , [LastName] [nvarchar] (100) COLLATE Chinese_PRC_CI_AS NULL , [Country] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL , [Note] [nvarchar] (2000) COLLATE Chinese_PRC_CI_AS NULL  ) ON [PRIMARY] GO 插入数据:(2万条,用更多的数据测试会明显一些) SET IDENTITY_INSERT TestTable ON declare @i int set @i=1 while @i<=20000 begin insert into TestTable([id], FirstName, LastName, Country,Note) values(@i, 'FirstName_XXX','LastName_XXX','Country_XXX','Note_XXX') set @i=@i+1 end SET IDENTITY_INSERT TestTable OFF ------------------------------------- 分页方案一:(利用Not In和SELECT TOP分页) 语句形式: SELECT TOP 10 * FROM TestTable WHERE (ID NOT IN (SELECT TOP 20 id FROM TestTable ORDER BY id)) ORDER BY ID SELECT TOP 页大小 * FROM TestTable WHERE (ID NOT IN (SELECT TOP 页大小*页数 id FROM 表 ORDER BY id)) ORDER BY ID ------------------------------------- 分页方案二:(利用ID大于多少和SELECT TOP分页) 语句形式: SELECT TOP 10 * FROM TestTable WHERE (ID > (SELECT MAX(id) FROM (SELECT TOP 20 id FROM TestTable ORDER BY id) AS T)) ORDER BY ID SELECT TOP 页大小 * FROM TestTable WHERE (ID > (SELECT MAX(id) FROM (SELECT TOP 页大小*页数 id FROM 表 ORDER BY id) AS T)) ORDER BY ID ------------------------------------- 分页方案三:(利用SQL的游标存储过程分页) create procedure XiaoZhengGe @sqlstr nvarchar(4000), --查询字符串 @currentpage int, --第N页 @pagesize int --每页行数 as set nocount on declare @P1 int, --P1是游标的id @rowcount int exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output select ceiling() as 总页数--,@rowcount as 总行数,@currentpage as 当前页  set @currentpage=(@currentpage-1)*@pagesize+1 exec sp_cursorfetch @P1,16,@currentpage,@pagesize  exec sp_cursorclose @P1 set nocount off 其它的方案:如果没有主键,可以用临时表,也可以用方案三做,但是效率会低。 建议优化的时候,加上主键和索引,查询效率会提高。 通过SQL 查询分析器,显示比较:我的结论是: 分页方案二:(利用ID大于多少和SELECT TOP分页)效率最高,需要拼接SQL语句 分页方案一:(利用Not In和SELECT TOP分页) 效率次之,需要拼接SQL语句 分页方案三:(利用SQL的游标存储过程分页) 效率最差,但是最为通用 在实际情况中,要具体分析。 分类: SQL 本文转自左正博客园博客,原文链接:http://www.cnblogs.com/soundcode/archive/2012/09/18/2691093.html,如需转载请自行联系原作者
文章
SQL  ·  存储
2017-10-10
oracle,mysql,SqlServer三种数据库的分页查询
MySql: MySQL数据库实现分页比较简单,提供了 LIMIT函数。一般只需要直接写到sql语句后面就行了。LIMIT子 句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,如果给出两个参数, 第一个参数指定返回的第一行在所有数据中的位置,从0开始(注意不是1),第二个参数指定最多返回行数。例如:select * from table WHERE … LIMIT 10; #返回前10行select * from table WHERE … LIMIT 0,10; #返回前10行select * from table WHERE … LIMIT 10,20; #返回第10-20行数据   Oracle: 考虑mySql中的实现分页,select * from 表名  limit 开始记录数,显示多少条;就可以实现我们的分页效果。 但是在oracle中没有limit关键字,但是有 rownum字段 rownum是一个伪列,是oracle系统自动为查询返回结果的每行分配的编号,第一行为1,第二行为2,以此类推。。。。 第一种:   复制代码 代码如下: SELECT * FROM (                   SELECT A.*, ROWNUM RN                    FROM (SELECT * FROM TABLE_NAME) A                    WHERE ROWNUM <= 40)WHERE RN >= 21       其中最内层的查询SELECT * FROM TABLE_NAME表示不进行翻页的原始查询语句。ROWNUM <= 40和RN >= 21控制分页查询的每页的范围。 上面给出的这个分页查询语句,在大多数情况拥有较高的效率。分页的目的就是控制输出结果集大小,将结果尽快的返回。在上面的分页查询语句中,这种考虑主要体现在WHERE ROWNUM <= 40这句上。 选择第21到40条记录存在两种方法,一种是上面例子中展示的在查询的第二层通过ROWNUM <= 40来控制最大值,在查询的最外层控制最小值。而另一种方式是去掉查询第二层的WHERE ROWNUM <= 40语句,在查询的最外层控制分页的最小值和最大值。 第二种:   复制代码 代码如下: select * from (select e.*,rownum  r from  (select * from emp order by sal desc) e ) e1 where e1.r>21 and e1.r<=40;       红色部分:按照工资降序排序并查询所有的信息。 棕色部分:得到红色部门查询的值,并查询出系统的rownum并指定上别名。这一句就比较关键,起了一个过渡的作用,首先要算出rownum来对红色部分指定上序号,也可以为蓝色外面部分用到这个变量。指定上查询的开始记录数和结束记录的条件。 蓝色部分:指定记录从第几条开始到第几条结束,取出棕色部门的值来作为查询条件的变量 总结:绝大多数的情况下,第一个查询的效率比第二个高得多。 SqlServer: 分页方案一:(利用Not In和SELECT TOP分页) 语句形式:   复制代码 代码如下: SELECT TOP 10 *   FROM TestTable WHERE (ID NOT IN (SELECT TOP 20 id FROM TestTable ORDER BY id)) ORDER BY ID   SELECT TOP 页大小 * FROM TestTable WHERE (ID NOT IN (SELECT TOP 页大小*页数 id FROM 表 ORDER BY id)) ORDER BY ID     分页方案二:(利用ID大于多少和SELECT TOP分页) 语句形式:   复制代码 代码如下: SELECT TOP 10 *   FROM TestTable WHERE (ID > (SELECT MAX(id) FROM (SELECT TOP 20 id FROM TestTable ORDER BY id) AS T)) ORDER BY ID   SELECT TOP 页大小 * FROM TestTable WHERE (ID > (SELECT MAX(id) FROM (SELECT TOP 页大小*页数 id FROM 表 ORDER BY id) AS T)) ORDER BY ID     分页方案三:(利用SQL的游标存储过程分页)   复制代码 代码如下: create procedure XiaoZhengGe   @sqlstr nvarchar(4000), --查询字符串 @currentpage int, --第N页 @pagesize int --每页行数 as set nocount on declare @P1 int, --P1是游标的id @rowcount int exec sp_cursoropen @P1 output,@sqlstr,@scrollopt=1,@ccopt=1,@rowcount=@rowcount output select ceiling(1.0*@rowcount/@pagesize) as 总页数--,@rowcount as 总行数,@currentpage as 当前页 set @currentpage=(@currentpage-1)*@pagesize+1 exec sp_cursorfetch @P1,16,@currentpage,@pagesize exec sp_cursorclose @P1 set nocount off     其它的方案:如果没有主键,可以用临时表,也可以用方案三做,但是效率会低。 建议优化的时候,加上主键和索引,查询效率会提高。 通过SQL 查询分析器,显示比较:结论是: 分页方案二:(利用ID大于多少和SELECT TOP分页)效率最高,需要拼接SQL语句 分页方案一:(利用Not In和SELECT TOP分页) 效率次之,需要拼接SQL语句 分页方案三:(利用SQL的游标存储过程分页) 效率最差,但是最为通用 在实际情况中,要具体分析。 
文章
SQL  ·  Oracle  ·  关系型数据库  ·  MySQL  ·  数据库  ·  移动开发  ·  存储  ·  索引
2014-11-16
Oracle开发与使用文章收藏
  收集一些Oracle开发与使用文章,以便于后续查找. 【基础类】 1.ORACLE函数大全 2.Orace常用函数 3.oracle 日期函数介绍 4.Oracle中常用的to_Char用法详解(有FMT的详细列表) 5.ORACLE中日期和时间函数汇总(转载) 6.SQL Server和Oracle常用函数对比 7.Oracle函数详解 8.Oracle 分析函数的使用 9.Oracle for Windows 相关下载地址 10.oracle 存储过程的基本语法 及注意事项 11.Oracle PL/SQL入门之慨述 12.oracle数据库的启动与关闭 13.Oracle数据库的体系结构 14.安装Oracle数据库时的注意事项 15.Oracle中Instance实例和数据库的区别   【开发类】 1.C#中利用Oracle事务删除表 2.Asp.Net 应用程序在IIS发布后无法连接oracle数据库问题的解决方法 3.将公司系统从Sql Server 2K移植到Oracle 10g中的简要总结 4..net 2.0 访问Oracle --与Sql Server的差异,注意事项,常见异常 5.Asp.net中SQL/Oracle通用分页控件 6.ASP.NET调用oracle存储过程实现快速分页 7..Net 中读写Oracle数据库的两种方式 8..NET调用Oracle存储过程,使用数组类型的参数(如ArrayList) 9.通过.NET访问 Oracle数据库 10.在 .NET 中使用 Oracle 数据库事务 11.Asp.Net访问Oracle 数据库 执行SQL语句和调用存储过程 12.Oracle在.Net开发上的一点经验 pcsky(原作) 13.运用C#处理lob数据类型 (Oracle) 14.C#调用Oracle带有out游标参数存储过程的问题 15.C# 操作 XML 数据库类型、Oracle XMLType 16.C#调用ORACLE存储过程返回结果集及函数    【管理类】 1.Oracle常用数据字典表操作 2.[转]Oracle常用命令 3.ORACLE EXP/IMP 参数详解 4.Oracle中使用同义词 5.Oracle利用job实现定时执行任务 6.Oracle跨数据库的数据操作 7.Oracle数据库日常维护 8.Oracle数据库的备份方法 9.Oracle 数据库的安全策略 10.管理Oracle数据库要注意的一些问题 11.oracle数据库优化 12.oracle 数据库备份和还原   【其它】 1.ORA-00911错误及解决方法 2."ORA-00942: 表或视图不存在 "的原因和解决方法 3.Oracle临时表空间不够,导致查询出错。 4.详细讲解大型数据库的设计原则与开发技巧 5.奇怪的"未明确定义列”错误 6.用Coalesce函数代替长长的"when ...else"串 7.Oracle常见问题与解答 8.Oracle数据库资料收藏 9.SqlServer到Oracle数据库转换手记 10.通过命令来操作Oracle数据库的   本文转自peterzb博客园博客,原文链接:http://www.cnblogs.com/peterzb/archive/2009/06/09/1499999.html,如需转载请自行联系原作者
文章
SQL  ·  Oracle  ·  关系型数据库  ·  C#  ·  数据库  ·  存储  ·  数据格式  ·  XML  ·  Windows  ·  Perl
2017-03-06
Oracle开发与使用文章收藏
 收集一些Oracle开发与使用文章,以便于后续查找. 【基础类】 1.ORACLE函数大全 2.Orace常用函数 3.oracle 日期函数介绍 4.Oracle中常用的to_Char用法详解(有FMT的详细列表) 5.ORACLE中日期和时间函数汇总(转载) 6.SQL Server和Oracle常用函数对比 7.Oracle函数详解 8.Oracle 分析函数的使用 9.Oracle for Windows 相关下载地址 10.oracle 存储过程的基本语法 及注意事项 11.Oracle PL/SQL入门之慨述 12.oracle数据库的启动与关闭 13.Oracle数据库的体系结构 14.安装Oracle数据库时的注意事项 15.Oracle中Instance实例和数据库的区别   【开发类】 1.C#中利用Oracle事务删除表 2.Asp.Net 应用程序在IIS发布后无法连接oracle数据库问题的解决方法 3.将公司系统从Sql Server 2K移植到Oracle 10g中的简要总结 4..net 2.0 访问Oracle --与Sql Server的差异,注意事项,常见异常 5.Asp.net中SQL/Oracle通用分页控件 6.ASP.NET调用oracle存储过程实现快速分页 7..Net 中读写Oracle数据库的两种方式 8..NET调用Oracle存储过程,使用数组类型的参数(如ArrayList) 9.通过.NET访问 Oracle数据库 10.在 .NET 中使用 Oracle 数据库事务 11.Asp.Net访问Oracle 数据库 执行SQL语句和调用存储过程 12.Oracle在.Net开发上的一点经验 pcsky(原作) 13.运用C#处理lob数据类型 (Oracle) 14.C#调用Oracle带有out游标参数存储过程的问题 15.C# 操作 XML 数据库类型、Oracle XMLType 16.C#调用ORACLE存储过程返回结果集及函数    【管理类】 1.Oracle常用数据字典表操作 2.[转]Oracle常用命令 3.ORACLE EXP/IMP 参数详解 4.Oracle中使用同义词 5.Oracle利用job实现定时执行任务 6.Oracle跨数据库的数据操作 7.Oracle数据库日常维护 8.Oracle数据库的备份方法 9.Oracle 数据库的安全策略 10.管理Oracle数据库要注意的一些问题 11.oracle数据库优化 12.oracle 数据库备份和还原   【其它】 1.ORA-00911错误及解决方法 2."ORA-00942: 表或视图不存在 "的原因和解决方法 3.Oracle临时表空间不够,导致查询出错。 4.详细讲解大型数据库的设计原则与开发技巧 5.奇怪的"未明确定义列”错误 6.用Coalesce函数代替长长的"when ...else"串 7.Oracle常见问题与解答 8.Oracle数据库资料收藏 9.SqlServer到Oracle数据库转换手记 10.通过命令来操作Oracle数据库的   本文转自peterzb博客园博客,原文链接:http://www.cnblogs.com/peterzb/archive/2009/06/09/1499999.html,如需转载请自行联系原作者。
文章
SQL  ·  Oracle  ·  关系型数据库  ·  C#  ·  数据库  ·  存储  ·  数据格式  ·  XML  ·  Windows  ·  Perl
2017-05-12
OEA ORM中的分页支持
 本篇博客主要描述分页的常见技术方案,以及在 OEA 框架中的分页的应用及实现原理。   分页的几种方案     分页是解决大数据量显示的有效方法。根据分页技术应用的位置不同,大致可以把分页分为以下几种: 界面层分页      界面层的分页,类似于界面的虚拟化技术,是只显示需要的数据的一种技术。OEA 的 WPF 界面中目前已经实现了 UI 虚拟化,所以不再实现界面层分页。 优点: * 简单。许多控件都支持在界面层直接进行分页。 * 换页时,响应快。(在 C/S 结构下使用这种方案,数据都已经到达客户端,所以在分页时不需要额外的数据查询,响应速度较快。) 缺点: * 不用于太大的数据分页。由于没有减少网络传输,首次加载时较慢,需要把所有数据都传输到客户端。 实体层分页     在实体层进行分页操作的方案,很少会被使用。它是把查询出来的数据,在服务器端都转换为实体,然后再找到具体页的实体数据,其它的数据则直接丢弃。 优点: * 减少了首次的网络传输,对于客户端而言,调用的是分页的 API。 * 简单。 * 通用性强,与数据库无关,方案可以跨多种数据库。 * 统计总行数不需要发起二次查询。 缺点: * 占用内存,依然不能用于太大的数据分页。 数据层分页      这种方案一般使用 IDataReader 实现。查询的 SQL 依然是查询所有的数据,但是在对查询出的 IDataReader 进行遍历读取每一行时,只读取对应页的数据,其它页的数据则忽略。同时,遍历到记录集的最后一行,即可获得数据的总行数。 优点: * 不占用大量内存。只把需要的数据读取到内存中。 * 简单。 * 通用性强,与数据库无关,方案可以跨多种数据库。 * 统计总行数不需要发起二次查询。 缺点: * 查询的 SQL 会查询很大的一张表。遍历依然需要耗费一定的时间。 数据库分页      分页的最终方案,自然是在数据库中进行分页。这也是大多数情况会选用的方案。 优点: * 性能最好。速度快、占用内存小。 * 统计行数时,往往需要重新发起查询。 缺点: * 对于框架开发而言,要生成分页相关的 SQL,较麻烦。 * 方案与特定数据库相关。通用性低。     虽然提到了这几种不同层面的分页方案。但是对应应用开发而言,数据库的分页是最常用的。只是在做 OEA 框架开发时,由于要支持多种数据库,所以需要在合适时采用不同的方案。同时,也不会考虑使用存储过程来辅助分页。 OEA 分页 - 应用层接口     在说明 OEA 的分页前。先介绍一个 PagingInfo 类型(老版本中,该类名为 PagerInfo),这关系到整个分页方案的接口设计: 图1 位于 Common(原 hxy)程序集中的 PagingInfo 类型 图2 PagingInfo 类型接口     在查询数据时,我们指定了查询的具体页码 PageIndex、一页所含数据行数 PageSize,就可以把该页的数据显示在界面上了。但是,在分页时,往往要在界面中显示一个分页脚,用于显示当前页号、所有页数。所以在进行查询的同时,往往还需要对结果集中所有数据的总行数进行统计,并把之与查询出的实体列表数据一同返回。所以,我为 PagingInfo 添加了额外的两个属性,IsNeedCount、TotalCount,当 IsNeedCount 被设置为真时,框架在数据层进行查询时,会把统计出来的总行数赋值给 TotalCount。   OEA 分页 - 使用方法     下面以分页查询所有数据为例,简单说明如何使用分页查询。先是应用层使用的代码: 应用层需要构造 PagingInfo,并指定需要统计行数。查询后,直接使用 PagingInfo.TotalCount。(这种接口方案从 06 年使用至今,比较好用。) 下面是 Repository 类型上的公有接口: 最后,再实现该查询对应的数据层即可: 可以看到,在数据访问层的 ORM 框架中,主要是在 IQuery 条件类型上添加了一个 Paging 方法。使用这个方法指定了 PagingInfo 后,即按给定的分页信息分页查询实体数据了。 OEA 中的数据层分页实现      OEA 中用到的分页有:界面层分页、DataReader 分页、数据库分页。 界面层分页  其实在 OEA 中就是 UI 虚拟化。相关内容,可以查看《OEA 中 WPF 树型表格虚拟化设计方案》 及 《 精通 WPF UI Virtualization》。    数据库分页(分页SQL)     目前,OEA 已经支持了 SqlServer 2005+、Oracle 10+、SqlCE4+,但是框架的设计目标则是应对所有数据库(接下来很可能需要对 MySql 进行支持)。这三种数据库中,OEA 只支持前两种大型数据库的数据库分页,主要是生成分页 SQL 进行查询。     经过对比、挑选,我选用了一种可以在 SqlServer、Oracle 上的一种通用方案,即使用 RowNumber。例如,如果一个 SQL 查询是: select ...... from ...... order by xxxx asc, yyyy desc ,则只需要把它转换为以下格式就行了: select * from (select ......, row_number() over(order by xxxx asc, yyyy desc) _rowNumber from ......) x where x._rowNumber<10 and x._rowNumber>5 。     同时,当需要统计总行数时,数据层会生成 SELECT COUNT(0) FROM ...... 的 SQL 语句重新进行查询,并把结果赋值给 PagingInfo.TotalCount,以及 EntityList.TotalCount。     在 SQLCE 中,并不支持 rowNumber 函数。所以只能考虑使用 NOT IN 的 SQL 方案。其实在OEA中,鉴于实现 NOT IN 方案比较麻烦,所以决定暂时使用 DataReader 完成 SQLCE 的内存分页。   DataReader 内存分页      提供 DataReader 方案主要是简单、同时还能与数据库无关,解决跨库问题。主要逻辑代码如下: /// <summary>  ///使用 IDataReader 的内存分页读取方案。 ///  ///注意!!! /// 此方法中会释放 Reader。外层不能再用 Using。 /// </summary>  /// <param name="reader"></param>  /// <param name="rowReader">每一行数据,会调用此方法进行调取。</param>  /// <param name="pagingInfo">分页信息。如果这个参数不为空,则使用其中描述的分页规则进行内存分页查询。</param> public static void MemoryPaging(IDataReader reader, Action<IDataReader> rowReader, PagingInfo pagingInfo = null)  {      bool isPaging = pagingInfo != null;      bool needCount = isPaging && pagingInfo.IsNeedCount;      int totalCount = 0;      int startRow = 1;//从一开始的行号      int endRow = int.MaxValue;      if (isPaging)      {          startRow = pagingInfo.PageSize * pagingInfo.PageIndex + 1;          endRow = startRow + pagingInfo.PageSize - 1;      }      using (reader)      {          while (reader.Read())          {              totalCount++;              if (totalCount >= startRow)              {                  if (totalCount <= endRow)                  {                      rowReader(reader);                  }                  else                  {                      //如果已经超出该页,而且需要统计行数,则直接快速循环到最后。                      if (needCount)                      {                          while (reader.Read()) { totalCount++; }                          break;                      }                  }              }          }      }      if (needCount)      {          pagingInfo.TotalCount = totalCount;      }  } 通用,又简单。   待改进点 目前实现上,可能存在的缺陷是: 对分页 SQL 的转换不支持复杂的嵌套 SQL。这时可能出错。   希望大伙拍砖。
文章
SQL  ·  关系型数据库  ·  数据库  ·  C#  ·  虚拟化
2016-05-05
ASP.NET 实用资料[转]
使用SqlBulkCopy类加载其他源数据到SQL表 在数据回发时,维护ASP.NET Tree控件的位置 vagerent的vs2005网站开发技巧 ASP.NET2.0小技巧--内部控件权限的实现 图片滚动代码。 css——之三行三列等高布局 Datagird TemplateColumn类型列中如何设定日期格式为yyyy-MM-dd格式? SQL Server各种日期计算方法 在sqlserver中如何根据字段名查找字段所在的表 [CommunityServer]看RBAC的一方景象 七招制胜ASP.NET应用程序开发 企业库之数据访问的一个小应用 SQL查找某一条记录的方法 简介微软发布的Data Access Application Block 把Excel表中的数据导入数据库(存储过程、数据库作业) 通过避免下列 10 个常见 ASP.NET 缺陷使网站平稳运行(转) 一个分组查询的SQL 常用算法(附源码可直接执行) 网络蜘蛛(crawlers) ,SEO,网络公关等相关资源与工具的收集与整理 最新版FreeTextBox(版本3.1.6)在ASP.Net 2.0中使用简解(提供博客园本地下载) 经典数据库记录分页代码 [GridView控件]自定义分页 Web C#2.0 DataSet和Reader封装组件实现自动多数据库切换(含组件源码和实例) 为GridView删除添加提示 扩展GridView(五)——固定表头、指定行或指定列 Asp.net 2.0 Treeview 无限级无刷新示例 运用JAVASCRIPT,写一个类,类名:student,他的属性:name,age,tall,他的方法:getName,getAge,getTall SQL IF..ELSE..在存储过程的使用规范 sql server日期时间函数 页面自动刷新 css的一些基础的东西 利用css和js实现firefox和IE都支持的页面局部打印 总结一些js自定义的函数 從無到有實現一個xml數據庫登錄驗証 图片保存到数据库和从数据库读取图片并显示(C#) [转]FreeTextBox使用详解 将上传图片打上防伪图片水印并写入数据库 asp.net 2.0中一次性更新所有GRIDVIEW的记录 VS2005 TreeView 的 CheckBox 被点击时的引发页面回发事件 扩展GridView(四)——每行复选框的全选与取消全选 [翻译]开发一个HTML在线编辑器(一) Castle ActiveRecord(一)概述 用sql 得到某表下的列名 一个二级域名转向类(转) sql 分页存储过程 sql2000下 分页存储过程 回归命令行 SQLServer的命令行工具们(2) – sqlcmd.exe(中篇) 分页及页码导航 用户控件 十分钟内学会:根据数据库生成站点导航 自己写的几个高效,简洁的字符处理函数 用一句SQL取出第 m 条到第 n 条记录的方法 老问题:js实现gridview中的全选和反选 js取得gridview中获取checkbox选中的值,郁闷了半天 JavaScript 经典代码大全:有 目录 及 编号 的哦 ! 深入DML JavaScript 網頁打印處理 HTML语言:经典笔记'800')this.width='800';if(this.height>'600')this.height='600';" border=0> 员工管理系统(数据库部分)--一个老师很久就布置的作业 CSS 实用笔记 数据仓库自动抽取:通过 SQL Server 企业管理器中的数据转换服务 (DTS) 设计器 创建 Analysis Services 处理任务 SQL Server各种日期计算方法 如何创建类型FreeTextBox的编辑器 MemberShip(图) 让你的ASP.NET虚拟主机也支持子网站 使用 SqlBulkCopy 大量复制文字文件之 C# 程序代码 Community Server 2.1 安装到远程虚拟主机上常见问题解决 (摘)开源AJAX开发框架 继续发布VS2005下DataGridView 的多种样式列控件 sql server作业用法 SQL2000 和 SQL2005 下 行列转换 示例 使用批处理产生日期(时间)文件、文件夹 ASP.NET 2.0 Security FAQs 效果直逼flash的Div+Css+Js菜单 一个二级域名转向类(转) ASP.NET分页系列转载 (转载)基于.net开发平台项目案例集锦 轻松学DIV教程(div+css布局) 如何让SELECT 查询结果额外增加自动递增序号 导出sql server 数据库为Excel的数据字典的小工具 使用Gridview和ObjectDataSource轻松实现自定义分页 在数据回发时,维护ASP.NET Tree控件的位置 除非迫不得已不要用游标 基于.NET的CMS软件的选择 搜索引挚项目(附源码) 重写GridView分页样式! 重写GridView 开源代码生成器:SmartCode 构建基于ListView(Win)的数据绑定对象 随心所欲的Web页面打印技术 扩展GridView控件(上) Gridview动态隐藏空字段 ASP.NET组件DataGrid的分页实用方法 基于角色-功能-资源的权限控制模型的设计与实现 asp.net 2.0 权限树的控制(多处转载) Castle ActiveRecord Hands On Lab(1):基本数据访问 如何在数据层分页以提高性能 为gridview添加删除提示。 解决ASP 2.0中GridView控件的删除、插入、编辑命令操作客户端确认问题的另一方法 基于.net开发平台项目案例集锦 EnterPrise应用(5) Security Application Block应用程序块 授权处理(VB.NET) Ajax实现无刷新三联动下拉框 ASP.NET 2.0打造购物车和支付系统之 一 ASP.NET 2.0打造购物车和支付系统之二 通过样式表实现固定表头和列 数字转换为大写人民币(附源码)_AX 使用RewritePath方法实现【不同路径+任意URL后缀重写到指定页面且URL地址不变】(附源码)_AX 基于.net开发平台项目案例集锦 效果直逼flash的Div+Css+Js菜单 一段非常简单的让图片自动切换js代码 ASP.NET弹出一个对话框 通过样式表实现固定表头和列 在VS2005中 GridView导入Excel的两点小技巧-附源码 asp.net 2.0 中GridView里设置日期格式 针对Enterprise Library 2.0的框架:OFrame预览(代码和工具全部开源) {asp.net2.0}##一个关于GridView的网站 障眼法--如何去掉动网新闻系统的版权信息 ASP.NET简单分页 NQL.NET 数据库对象查询语言简介 2 Asp.Net 学习资源列表 asp.net身份验证和授权 在VS2005中 GridView导入Excel的两点小技巧-附源码 [转载]Asp.Net 2.0 发布问题 权限树中Checkbox的操作[Asp.Net2.0] 如何于DataGridView控件中以跨数据行方式显示数据 asp.net2.0中,实现treeview中选择父级checkbox时,子级连动 整理转载 自定义DataGrid控件开源 [视频讲解]GridView里做链接实现新闻列表到详细内容页的跳转 『原创』以学论道之ASP.NET中的文件流操作 GridView控件自定义分页详解 3-tier Architecture with ASP.NET 2.0 : Tutorial By Scott Mitchell TreeViewVisitor: 一个快捷访问 TreeView 控件节点的帮助类 基于功能(代码)的权限管理 一步一步学习ObjectDataSource控件--自定义分页排序 自己编写的操作实体类的分页控件, 实现页码层与数据库的具体的信息隔离 Alexa世界排名原理+作弊源码,为网站赢得好排名 Ajax实现无刷新树 GridView 批量删除,自定义分页,定位页码 关于GridView中自定义分页、单选、多选、排序、自增列的简单应用 Ajax实现无刷新三联动下拉框 GridView模版列嵌套GirdView显示主从表数据 Ajax无刷新实现图片切换特效 asp.net 2.0 用户管理功能结构 Asp.Net2.0权限树中Checkbox的操作 Membership学习(二)membership入门[xgluxv] Membership学习(三)Membership Providers介绍[xgluxv] Membership学习(一) Membership介绍[xgluxv] Membership学习(四)-自定义MembershipProvider Gridview中当设置自动生成列时对列中字段使用 html代码显示 一点一点学ASP.NET之示例——HttpModule 示例 一个三层架构的WinForms程序的完整范例(.NET 1.1/Northwind) 发布XenoCode 2006 for DotNet 2.0破解程序 一个简单的存储过程 Css2快速参考 在b/s开发中经常用到的javaScript技术 NHibernate的灵活配置 搭建基于ASP.NET 2.0的DNN 4.X模块开发环境及模块实例(2) 搭建基于ASP.NET 2.0的DNN 4.X模块开发环境及模块实例(1) 发布一个支持大量文本打印的PrintDocument派生对象,公开源代码。 史上最全的Windows进程详解! PetShop4.0学习第一天 删除前的确认窗口 我对图形变换滤镜的收集(CSS渐变滤镜大全) 2006年it人士必去的10个网站 DataReader应用小示例(数据库访问操作的基本过程2.0通过) (收藏)抓取Web网页数据分析 GridView/DataGrid单元格不换行的问题 如何在GridView中使用DataFromatString VS2005新控件之GridView 使用高级技巧系列[一][视频] VS2005新控件之GridView 使用高级技巧 几个.Net开源的CMS、Portal系统 gridview中加弹出窗口用例 GridView&DetailsView对XML文件增删改 [译]Scott Mitchell 的ASP.NET 2.0数据教程之十一: 基于数据的自定义格式化 初谈ADO.NET中利用DataAdapter进行数据操作 单一登录 Web 应用程序的企业级安全系统 发布XenoCode 2006 for DotNet 2.0破解程序 IBatisNet+Castle构架开发指南 IBatisNet+Castle构架开发指南 (续) 附代码生成模板 GridView根据值的变化改变行列样式 使用ASP.NET 2.0中的GridView控件 我积累的数据库操作类(ASP.NET) 我积累的数据库操作类(ASP.NET) 我积累的数据库操作类(ASP.NET) GridView 控件编程的事件 css+div布局总结--新手入门 15分钟内快速构建数据访问层(翻译) Transact_SQL小手册(各种sql语句大集合) Exports datatable to CSV or Excel format [转贴]开发VS2005下ComboBoxTreeView(下拉列表框弹出树) 与ToolStripComboBoxTreeView(下拉列表框工具条弹出树) 使用配制文件定制身份验证和基于角色的安全 一句SQL得出表中重复的数据(TMP) SQL精妙语句 Asp.net2.0:如何使用ObjectDataSource(配合ORM) Sql Server数据库的备份和恢复措施 SQL Server2000数据库文件损坏时如何恢复 存储过程编写经验和优化措施 (转) 征集佳句-精妙SQL语句收集 利用WebBrowser彻底解决Web打印问题 各种sql语句大集合 自定义用户访问权限 DataGrid导出excel和word的例子 具有滚动条的div SQL Server 2005 Express 附加的数据库为“只读”的解决方法 Sql 导入/导出Excel 不走寻常路 设计ASP.NET应用程序的七大绝招 ASP.NET性能优化 ASP.NET性能优化 对数据库Sql Server常用操作类库SQLHelper 如何取出treeview中checkbox的值 海量数据库的查询优化及分页算法方案 使用配制文件定制身份验证和基于角色的安全 VS2005新控件之GridView 使用高级技巧系列[二][视频] 一条经典的汇总的sql sql Server 索引优化 (转) Log4Net使用指南 一些有用的sql语句实例 Enterprise Library 2.0 -- Data Access Application Block 在Excel中将连续多列相同数据项合并 执行SQL存储过程事事例 SQL宝典 SQL语句导入导出大全(轉,收藏用)  gridview中手工排序 Asp.net 项目中引入Nhibernate 入门(一) 利用asp.net 2.0的客户端回调功能制作下拉框无限级联动 一个 NHIBERNATE+GRIDVIEW 添加删除修改的例子(单表) IBatisNet基础组件 用javascript将数字转换为中文大写 asp.net的TextBox回车触发事件 利用Sql作业在asp.net 里面实现异步调用存储过程. 抓取Web网页数据分析 VS2005中如何动态设置数据库连接信息? GridView控件修改、删除示例(修改含有DropDownList控件) JavaScript有用的代码,摘抄自:http://bbs.tech.163.com/board/rep.jsp?b=tech10&i=1296&p=0[转] 一些sql语句的详细解释 DataGrid使用心得(附大量代码) [转] SQL Server中各个系统表的作用 使用 Web Services Enhancements 2.0 的基于角色的安全性 Flash+asp.net打造FLASH首页新闻发布 SQL存储过程事务和优化方法(包括查询方式语句结合) 小记存储过程中经常用到的本周,本月,本年函数 GridView Css ASP.NET 2.0 Language Swithcer and Theme Swiche ASP.net2.0学习资料汇总 触发器与约束的适用条件 GRIDVIEW 中当数据行数未满时,填充空白行 ComponentArt Web.UI for ASP.NET 2.X序列号 创建用于监视对student表进行插入和更新操作的触发器 20060516: 实现圆角div效果 .net绝对技术资料 sql server2000中使用convert来取得datetime数据类型样式(全) 一些sql 语句(行列转换等) [转载] Owc的使用---自己封装好的类可以实现14种分析图 非常經典的WEB列印方案 CuteEditor 5.0 的使用 ASP.NET 2.0构建动态导航的Web应用程序(TreeView和Menu ) MD5算法的T-SQL实现 ASP.NET2.0中数据源控件之异步数据访问 DotNetGrid 控件下载 DotNetGrid 介绍 WEB打印-------我的搜集 在校生数据导入范例 关于多极分类的几个存储过程 一个 NHIBERNATE+GRIDVIEW 添加删除修改的例子(单表) 树形数据查询示例 转 SQL Server 数据库管理常用的SQL和T-SQL语句 IIS状态代码的含义 .NET平台下带权限控制的TreeView控件节点生成算法(转载) 实现HTTP内容的抓取 给SQL Server存储过程,传送数组参数的变通办法 在.net中使用Fckeditor [转] SQL的3种连接查询 海量数据库的查询优化及分页算法方案 [转] transact---sql高级查询(下) [转] transact---sql高级查询(上) SQL Server数据库开发的二十一条军规 Excel编程 存储过程语法 SQL 语法参考手册 ASP.NET之精通弹出窗口 在网页中插入视频播放代码全集 无限级分类的实现 资源名称资源名称取得汉字字符串的拼音首字母的mssql函数 树_ajax 树_ajax GridView与DataGrid中的数据项访问差别 Gridview中onmouseover的效果 ASP.NET2.0+SQL Server2005构建多层应用(转载) 修正过的通用分页存储过程 [推荐]网络上通用的调查答卷系统-XML做数据库(将DataSet转化成字符串) MS-SQL数据库开发常用汇总 在visualStudio里面使用SqlServer2000作为数据源 获取影响行数和ID的存储过程 C# .Net中的类型转换 C#.net常用函数 SQL注入 FCKeditor2.2+ASP.NET2.0不完全攻略 FCKeditor2.2+ASP.NET2.0不完全攻略 【转贴】datagrid数据导出到excel文件给客户端下载的几种方法 GridView动态生成模板列 关于树形控件 asp.net 备份和恢复SQL SERVER 数据库 Asp.net(C#)实现验证码功能 Asp.NET程序中常用的三十三种代码 分割以逗号作为分割符号的字符串并插入到表中 列出一个表中的某个字段重复的记录 DataGrid系列技巧(导出excel,事件,多种方式呈现数据,全选全删)等等等 把以"文本文件(制表符分割)"保存的EXCEL文件导进SQLSERVER2000的DEMO! 总结:ADO.NET在开发中的部分使用方法和技巧 (转贴) DATAGRID的全选/取消全选控制(CHECKBOX) 使用SqlBulkCopy类加载其他源数据到SQL表 使用SqlBulkCopy类加载其他源数据到SQL表 使用SqlBulkCopy类加载其他源数据到SQL表 一个调查实例<主要训练向panel中添加控件>包括全部代码 ASP.NET 2.0客户端回调的实现分析(3)[ZT] [原创]把SQL的动态查询改成SQL查询 SQL Server实用经验技巧集 使用 DataAdapter 执行批量更新 treeview的建立,更新,删除 C#实现web信息自动抓取 [收藏].net关于企业Excel报表的生成 将 ASP.NET 2.0 应用程序服务配置为使用 SQL Server 2000 或 SQL Server 2005(转) .NET进销存系统开发笔记------之Gridview应用 .net 2.0中GridView无限级嵌套的实现 导入Excel电子表格数据到SQLSever数据库的另一种方法 一个购物车的简单实现(多层开发) ASP.NET2.0中 TreeView 和ORACLE 数据绑定的一种方法 ASP.NET2.0 ObjectDataSource的使用详解(2) ASP.NET2.0 ObjectDataSource的使用详解(1) 将DataSet更新自动提交到数据库工具类实现 超强扩展性的DNN-DotNetNuke模块功能分类列表(from 中国DNN) 世界上主要的一些搜索引擎 Survey Admin 示例:实现 Microsoft .NET 基于角色的安全性(转) NHibernate Step by Step (四)Session、Query及HQL NHibernate Step by Step (三) Configuration和Sessionfactory Microsoft .NET Pet Shop 4 架构与技术分析 PetShop的系统架构设计 Asp.Net 2.0 TreeView的Checkbox级联操作 无废话-SQL Server 2005新功能(1) - TSQL 导出导入Excel(DataSet,DataGrid) DNN开发中的一些细节(1) DNN开发中的一些细节(2) ASP.NET2.0: Ilungasoft.Framework.Web之基于Callback的无刷新上传进度条控件[带源码] TreeView 爱恨之间 Transact SQL 常用语句以及函数 Transact SQL 常用语句以及函数 ASP.NET 2.0 正式版中无刷新页面的开发 DNN开发中的一些细节(1) ASP.NET2.0快速入门--高级数据方案(3) 结合CodeSmith开发和调试DNN3模块 SqlDataSource WEB控件:当DeleteCommandType="storedProcedure"时 关于TreeView控件专题 利用Treeview做权限树的一种方法 利用Treeview做权限树的一种方法 (新)在ASP.NET中调用存储过程传参数 ASP.NET2.0快速入门系列--高级数据方案(上) ASP.NET2.0快速入门--高级数据方案(中) asp/asp.net中遍历树型结构. ASP.NET 2.0中使用multiview控件 ASP.NET2.0快速入门系列--高级数据方案(上) DataGrid,GridView和DetailsView中添加删除确认提示 VS2005中用Code Snippets提高开发效率 IIS和ASP.NET2.0 关于vs 2005的一个问题, 解决The path "xxxx' maps to a directory outside this application, which is not supported. VS2005第一天 Failed to access IIS metabase 无ASPX文件部署(续) ASP.NET 2.0构建动态导航的Web应用程序(TreeView和Menu ) ASP.NET 2.0基于SQLSERVER 2005的aspnetdb.mdf部署 对vs2005生成dll文件的一点疑惑 ASP.NET 2.0 新特性 WEB Service 下实现大数据量的传输 switch your web application project to use development machine's IIS server [ASP.NET 2.0 Security FAQs]如何设置SQL Server或SQL Express数据库,使其支持Membership、Profiles和Role 将 ASP.NET 2.0 应用程序服务配置为使用 SQL Server 2000 或 SQL Server 2005(转载) GridView 控件使用不完全指南! 【原创】asp/asp.net中遍历树型结构. .NET Pet Shop 4.0案例研究预览篇 关于树形结构的研究的资料收集 单点登录(SSO)的核心--kerberos身份认证协议技术参考(三) Gridview:在进入编辑模式后动态添加控件 ASP.NET中大结果集的分页[翻译] Asp.Net Forums研究文章集合(收藏) ASP.NET2.0中Gridview中数据操作技巧 SQL Server中利用存储过程来高性能地进行分页 关于二级域名Cookie的问题及解决方法 一步一步建网-2-DotNetNuke4-5/6-杂项/感! 通过系统配置来提高ASP.NET应用程序的稳定性 GridView 控件使用不完全指南!(续一) ASP.NET应用程序的部署--兼谈aspnet_compiler.exe命令 RDLC报表(一) RDLC报表(七) GridView 控件使用不完全指南! DNN皮肤制作 一个登陆页面,包含了初始化用户,输入检测,错误处理等 DNN皮肤制作 基于dotnetnuke的网站全新上线! [导入]DotNetNuke Skin 與 Container 設計介紹 CodeSmith3.0开发资料下载 CodeSmith开发系列资料总结 提高SQL执行性能方案:如何让你的SQL运行得更快zt Visual Studio 2005 的101个示例下载 网络数据库挖掘程序的设计 对联广告代码效果大全 网站生成静态页面,及网站数据采集的攻、防原理和策略 [原创]终极防范SQL注入漏洞! 【先锋海盗类】Ver2005 完美版 拿别人的新闻来用,虽然我知道这样不好,还是用了。。。 网页小偷程序ASP.net 数据采集程序(网页小偷)点滴心得 部署安装时写入SQL SERVER和Web.config 将博客园程序从Visual Studio 2003迁移到Visual Studio 2005的尝试 开篇:Nhibernat.Test项目分析之:ConfigurationTest 基于NHibernate的三层结构应用程序开发初步 15分钟内快速构建数据访问层(翻译) Asp.net 2.0专题二:本地化(Localization) 数据库应用基础系列 深入了解 SQL Server 2000 与 ADO.NET 中的事务隔离及数据锁定 第2章 并发操作的一致性问题 (2) 在asp.net 2.0中使用SqlBulkCopy类迁移数据 使用asp.net 2.0和SQL SERVER 2005构建多层应用 推荐个关于 team system教学的好站点 推荐个关于 team system教学的好站点 DataList控件也玩分页- - SQL Server 两个触发器例子,大家看看怎么样? 发布一个原创的基于Ajax的通用(组合)查询(续) 在IIS6.0下ASP .NET 的版本冲突问题 FCKeditor应用小记--起步篇 WEB Service 下实现大数据量的传输 55种网页常用小技巧(转载) [转]Microsoft PetShop 3.0 [转载]用WSE在Web服务中验证用户身份 一次SQL Server 2000修复实践的说明 新数据网格DataGridView简介(转自MSDN) [转贴]Visual Studio 2005常用插件搜罗 第 4 章 构建以数据为中心的应用程序 网 站 策 划 [转载] 在.net安装程序部署SQL Server数据库 [转载] 在.net安装程序部署SQL Server数据库 ASP.NET程序中常用代码汇总(一)(转载) ASP.NET程序中常用代码汇总(二)(转载) ASP.NET程序中常用代码汇总(三)(转载) ASP.NET程序中常用代码汇总(四)(转载) ASP.NET程序中常用代码汇总(五)(转载) 露雨资源库(第一个.net2.0软件)二 ADO.NET 2.0 大批量数据操作和多个动态的结果集 继续发布VS2005下DataGridView 的多种样式列控件 一个支持asp.net2.0和Sql server及Access的免费空间 FAQ:关于aspspider.net的申请与使用(逐渐整理中) ASP.NET 2.0中的成员管理与角色管理 ASP.NET中用哪种方式表格化数据 DotNet软件开发框架 知识管理系统分析之一:网络蜘蛛的分析 如何实现在Asp.net下XP风格的下拉菜单 CodeSmith基础(二) CodeSmith开发系列资料总结 利用 SharpZipLib方便地压缩和解压缩文件 GridView控件使用经验 一个支持asp.net2.0和Sql server及Access的免费空间 新版XNet.SqlHelper 使用ASP.NET 2.0 Profile存储用户信息[翻译] Level 200 FreeTextBox使用详解 (版本3.1.1) Web Services的身份验证 [小结]关于asp.net个性化站点的设置 网络数据库挖掘程序的设计 使用企业程序库的两点体会 ASP.NET 2.0构建动态导航的Web应用程序(TreeView和Menu ) 如何使网站基于CA认证访问 体验 .net2.0 的优雅(2) -- ASP.net 主题和皮肤 一完美的关于请求的目录不存在而需要url重写的解决方案! 如何建立有效的.Net软件注册保护机制 常用CSS ASP.NET程序中常用代码汇总(五) ADO.NET 2.0 大批量数据操作和多个动态的结果集 在Apache环境下成功的运行ASP.NET 使用ADO.net转换数据到Excel格式并提供下载 打开一个Excel模板文件填充数据另存为一个文件 一个关于DataGrid的打印类,分享,感谢作者 把excel 数据导入数据库 NHibernate文档翻译 第5章 集合类(Collections)映射 NHibernate文档翻译 第4 章 O/R Mapping基础 关于能自定义格式的、支持多语言的、支持多数据库的代码生成器的想法 自动代码生成器 Enterprise Library Step By Step系列(十一):异常处理应用程序块——入门篇 Enterprise Library Step By Step系列(十):缓冲应用程序块——进阶篇 Asp.net中DataGrid利用DataRelation显示主从表信息(可控制从表信息隐藏和显示). Cookie 支持二级域名和FormsAuthentication 加强版 aspx->cs->dll 无aspx文件部署 无ASPX文件部署(续) asp.net报表解决方法(第一次使用cnblogs的blog) NHibernate文档翻译 第3章 持久化类(Persistent Classes) 《ASP.NET办公自动化系统开发实例导航》笔记三 人事管理模块 [转]Microsoft PetShop 3.0  《ASP.NET办公自动化系统开发实例导航》笔记二 系统管理模块设计 《ASP.NET办公自动化系统开发实例导航》笔记一 NHibernate文档翻译 第2章 ISessionFactory配置 TreeView常用操作 NHibernate文档翻译 第1章 体系结构 关于ASP.NET中调用Excel组件不能结束进程的解决方法 用ActiveX控件和JavaScript脚本实现基于Web的票据套打(源码下载) 搜索引擎, 请手下留情 我写的Asp.net操作Excel的一个类库ExcelHelper(源码下载) Enterprise Library Step By Step系列(八):日志和监测应用程序块——进阶篇 一个经典的ADO.NET入门例子(CSDN博客迁移) [源代码]系统框架NickLee.Framework.V1.X for asp.net asp.net利用OWC生成分析報表 把aspx文件编译成DLL文件 ADO.NET 2.0 大批量数据操作和多个动态的结果集 让.Text的搜索引擎支持二级域名 微软技术大会 Tech.Ed2005 所有讲义(ppt格式)下载地址 应用系统架构设计 应用系统架构设计-补全篇 简单实用的DATAGRID组件 .Text 支持二级域名之二 Cuyahoga的安装及结构 也nhibernate会遇到问题,还好找到原因了 [C#]NHibernate处理多帐套问题 滚动DataGrid 蛙蛙推荐:迎接web2.0:写一个RSS.HTC组件 分享:微软提供的一个开源控件treeview 的一小个用法 发布一个原创的基于Ajax的通用(组合)查询(续) 在ASP.NET页面中冻结DataGrid的列或头部 Cuyahoga代码的研究之一:Cuyahoga.Corel项目 Cuyahoga研究三:用户配置数据的处理 Cuyahoga研究之二:利用MD5CryptoServiceProvider返回字符串的MD5 Hash值 [精华&原创]可按任意字段排序的分页存储过程(不用临时表的方法,不看全文会后悔) Asp.net中把DataTable或DataGrid导出为Excel 技巧百问(5):打造超级浮动广告(不受屏幕限制) 使用HttpModule实现多个域名分别“绑定”到子目录 利用XML实现通用WEB报表打印 续:利用XML实现通用WEB报表打印(实现篇) 昨天的性能优化与今天的网站故障 一个关于DataGrid的打印类,分享,感谢作者 把文件上载到数据库中 .Text分页技术(1)分页的存储过程分析 Community Server专题十:MemberRole之RoleManager 构建动态导航的Web应用程序 SQL Server 用触发器实现表的历史记录 SQL Server 用触发器实现表的历史记录 WEB打印大全 asp.net操作Excel总结 VC++开发BHO插件——定制你的浏览器  作者 陆其明 如何实现在Asp.net下XP风格的下拉菜单 使用数据2分处理的通用分页存储过程 前半部分与后半部分数据访问时间相同(很久没来了 作为国庆礼物给大家了) Js控制ASPX页面刷新的土办法 代码生成工具之MyGeneration 初次体验.net Ajax无刷新技术 Community Server专题八:MemberRole之Membership 应用IBatisNet+Castle进行项目的开发 .Net PetShop3.0的数据访问技术及其改进 Community Server专题七: Job & Timer 使用企业库在某些站点会报试图执行安全策略不允许的操作异常的解决方法。 刚注册,先转发一片文章:在 ASP.NET 中执行 URL 重写 利用asp.net 2.0构建企业级门户平台(1、设计思想) 利用asp.net 2.0构建企业级门户平台(2、实现页面请求的调度) 报表的开发利器-ExcelQuicker ExcelQuicker模板功能的高级应用示例——薪资报表 SQL Server未公开的两个存储过程 WSE--简介(一) .net WebControl 处女作,用于导航的Tree控件(不敢说用起来最简单也算得上非常简单,呵呵) xml数据岛,xsl,javascript,asp.net 的结合使用 web 程序模仿 windows 资源管理器 用CodeSmith生成数据库实体类的代码 .NET中统一的存储过程调用方法(收藏) TreeView常用操作 NHibernate学习 NHibernate学习 给SQL Server存储过程,传送数组参数的变通办法 Community Server专题二:体系结构 权限设计(二) 通用分页存储过程 N-Tier Server/(Smart)Client 应用程序的设计和开发 基于身份验证票据的权限系统的实现之源代码篇 Enterprise LibraryV1.0-数据应用程序块 共享自动生成DTO/DataAccess/BizObject的CodeSmith模板 一个不错的SQL储存过程分页,储存过程+Repeater,如果只是浏览数据的话,快就一个字 Forms验证中的roles 跨页面的多选功能实现 简单说一下我对这个CRM系统的设计方案哦 把你的Access数据库嵌入到资源中发布 对象界面映射(UI Mapping)——Mustang1.0.0.0写完了!!! 蛙蛙推荐:利用OWC创建图表的完美解决方案 SQLServer 工具箱v1.3(SQL脚本排序,日志清除,数据导入导出)附完整源代码 从WEB SERVICE 上返回大数据量的DATASET 批量字符串替换程序 install shield X 打包 .net Framework ASP.NET直接下载一个文件,而不是在IE中打开它 实现GridView控件的删除多条记录功能系列(1) ComponentArt WebUI For asp.nET 2.1,So Good Asp.nET UI Control! 实现GridView控件的删除多条记录功能系列(2) 博客园 Google广告 开源项目 实现GridView控件的删除多条记录功能系列(3) ICSharpCode的SharpZipLib最新0.84版本 SmartDBForge-智能数据库工厂 2005预览版:自动化生成数据库文档、SQL脚本、实体类等,支持多种数据库 提供一个实体类生成工具. T-SQL 存储过程: (20050802修订版) 根据基本表结构及其数据生成 INSERT INTO ... 的 SQL 关于单点登陆的一些问题 蛙蛙推荐:微软MSDN导航菜单演示(Javascript+CSS2) 蛙蛙推荐:远程抓取网页到本地数据库.doc CuteEditor破解手记 [分享]FCKEDITOR范例及中文使用说明 [DNN模块开发]模块的文件结构及命名方法 用好CodeSmith,提高生产力,CodeSmith技术原理初探. Smart Client学习体会(一) 优秀.net 控件包介绍 应用系统架构设计 如何在删除并重新安装 IIS 之后修复 IIS 映射 五种常见的ASP.NET安全缺陷 “他说,你那样做,太累,而且如果字段变了,还要维护” 纯脚本搞掂DataGrid表表头不动,表身滚动。 DataGrid分页中文效果,与大家共享,顺便有能者把DropDownList的触发找到。我是放在呈现上。 基于文件格式的DataGrid多媒体播放示例(带表头自动排序,动态播放列表功能) Office自动化开发中的事件编程 ExcelQuicker模板功能的高级应用示例——薪资报表 抄:JavaScript实用技巧集锦 [分享]新封装的一个实现无刷新连动下拉列表类(最新版本) 新鲜出炉,几分钟以前刚刚完成,一个带自定义分页,排序功能的DATAGRID控件(公开源码) C#操作Excel,套用模板并对数据进行分页 Asp.Net Forums与现有系统整合方案示例 存储过程中的事务实现 基于Active Directory的用户验证 Sql server数据库记录修改追踪和恢复的解决方案 SQL Server最新补丁与工具大全--数据库管理员必看 介绍一种Web上打印技术 表单验证代码(转载) 在Webpart中以Post方式提交数据到SharePoint站点 ASP.NET2.0中用Gridview控件操作数据 一个有用的oracle数据库访问封装类 【经验分享】海量数据高性能分页新法 MSDN: 设计数据层组件并在层间传递数据 真的需要在.NET中使用WIN32 API的朋友,这里是你的宝库 服务器升级安装操作备忘[原创] WEB柱状图和折线图控件,大家应急时可以用用 RapidTier 1.0 beta2 发布 关于设置WebControls里的treeview控件的图片路径 两分钟让你明白什么是ERP! 权限控制理论及实现 纯脚本搞掂DataGrid表表头不动,表身滚动。 NHibernate 使用手迹(2nd) ASP.NET服务器控件开发简介: ComboBox [开放源代码] 用存储过程生成单据号 [开源论坛]StellaForum v 2.0 公开 NHibernate使用的问题 使用NHibernate时需要考虑的另一个问题 使用 DataAdapter 和 DataSet 更新数据库 绝对适合您的DataPropertyGrid! 关于BI Portal(一) 也谈log4net 1.2.9 beta的使用(web 项目) datagrid(webform)批量操作的一些思路。 将TreeView存储、写入数据库的扩展类TreeViewEx 一句SQL语句解决倒序数据分页提取 一个 TreeView 的派生类: TreeViewEx 实现 NodeShowToolTip、NodeDoubleClick 事件 解放程序员的验证输入(II) 用好CodeSmith,提高生产力,CodeSmith技术原理初探. 最近开发一个SQL server大数据量统计系统的经验总结 SQL语言高级技法演练 动态载入数据的无刷新TreeView控件(5) 动态载入数据的无刷新TreeView控件(4) 在ASP.Net中两种利用CSS实现多界面的方法. SQL Server数据汇总完全解析 asp.net学习资源列表 将TreeView存储、写入数据库的扩展类TreeViewEx .NET平台下WEB应用程序的部署(安装数据库和自动配置) 在sql语句中替换Not In 的方法 创建新的企业级模板 SQL Server游標應用技巧一例 送给所有还未买房的技术朋友们——住房按揭贷款计算器 基于Wiki的网络协作/知识积累试验平台 快过年回家了,发点实用的东西给大家 .NET商业应用架构所要解决的若干问题(原创) 企业设计模式读书笔记 Domain Model MAVERICK.NET初窥(原创) 再谈SQL Server表与Excel、Access数据互导 使用Singleton改善ASP.NET性能备注 石头.net [杨 云] 也来说说asp.net页面之间传递数据 Vs ColdFusion 一套可嵌入或独立使用的翻页控件: WebPager(附源码) Rainbow分页解决方案 我对多类型用户的设计想法...... 为什么叫“老师” 和 “学生” 生成工具-CodeSmith-享受编程的乐趣(三) 生成工具-CodeSmith-享受编程的乐趣(二) 生成工具-CodeSmith-享受编程的乐趣(一) 在ASP.NET中使用NHibernate 代码阅读总结之ASP.NET StartKit TimeTracker(角色权限之捉虫笔记) 一个NHibernate应用的实际例子(A good open source project to learn how to use NHibernate) 客户自行更改了aspnet用户权限,结果整个网站不能用。查找了资料记录下来 数据分页显示大搜索 CNBlogs引用第三方组(控)件明细^_^ 使用HttpContext的User属性来实现用户验证 近音搜索,比较输入Z就可以搜索到拼音Z开头的汉字,搜索"浙江",只要输入"ZJ"就可以了 看了下面那篇“Crack别人应用程序”的文章有感,简述.Net下的应用程序授权。 子查询基础知识 我用Rainbow做网站 将TreeView存储、写入数据库的扩展类TreeViewEx Dottext中的配置 提高ASP.NET应用程序性能的几招方法 一定要记住:Page.IsPostBack 不能忘。。。 log4net 配置与应用 浅析《ASP.Net Web 站点高级编程》的登录验证! 开源的数据库组件 代码阅读总结之ASP.NET StartKit TimeTracker(角色权限) 老猫的理想开源小范例 [精华&原创]可按任意字段排序的分页存储过程(不用临时表的方法,不看全文会后悔) IEWebcontrol webctrl_client目录配置 FMStocks7 , 不错的一个.NET 示例程序 感受DataGrid给数据操作带来的便利(4) 感受DataGrid给数据操作带来的便利(5) 中国DNN 的邀请 感受DataGrid给数据操作带来的便利(6) DotNetNuke(DNN)从入门到进阶(1)-怎样写自己的模块 如何实现文本框焦点自动跳转及通过回车键提交表单 如何使用一个不错的图表组件WebChart(免费) .NET下,你采用的是哪种方式进行数据操作? 两种不同情况的分页实现 .NET下,你采用的是哪种方式进行数据操作? 常用SQL说明 可以动态分页的存储过程 [专题]O/R 实体关系映射 我的IBatisNet的Demo DNN官方说明2 Duwamish代码分析篇 SQL Server数据库备份还原 通用分页SQL SQL过程自动C#封装,支持从表到基本存储过程生成, DNN的白皮书(官方说明) SQL Server自动备份的SP, 只要加上数据库名, 和路径即可. Rainbow中的不过期分页的文章Module 点击一个Button,来看Duwamish7的总体层次 我在研究的一些.net开源项目 回头看.Net的优点与进步 方便好用的 ASP.Net 错误记录发布模块 ELMAH (Error Logging Modules And Handlers) 我用Rainbow做网站 实现千万级数据的分页显示--整理资料并测试 小技巧之——服务器端变量与客户端JScript脚本变量的互操作。 Asp.net(C#)实现验证码功能 SQL 2000中的触发器使用 NHibernate 空气是哪么的清新,世界是多么的美好 NHibernate 做个小项目来试一下吧 三 NHibernate 做个小项目来试一下吧 四 (我们继续) 博客园的开源项目: Aop.NET DotNetAOP ibatis介绍[转贴] 使用open source产品组装你的web应用架构[转贴,只作为收藏,非本人原创] 发现不少免费、酷、强大组件(Win/Web) NHibernate 做个小项目来试一下吧 一 NHibernate 做个小项目来试一下吧 一 NHibernate 空气是哪么的清新,世界是多么的美好 用Nhibernate怎么实现数据的添加、删除、修改简单程序 利用webService做系统间数据整合 Rainbow的安装 我想问一下NHibernate的问题??? NHibernate学习第二天(在nhibernate中执行SQL语句 ) NHibernate学习第一天(数据的写入 Insert) 好久没有见到有人谈论代码生成器了 几个开源项目实体层实现方式比较 象使用DataGrid一样使用DataList(包含分页) 一个对众多CMS(内容管理系统)进行比较、评论的网站 在Windows下让不同用户使用不同的分辨率(C# 2005) 数据分页 DotNetNuke:如何创建自己的模块(FlashPlayer Module) SharpDevelop代码分析 (一、序+基本概念) 发布Asp.Net Forums V2 中文官方 10.1 国庆版 号外!激动人心的DotNetNuke(DNN)2.2x新特性最新汇报! DotNetNuke:制作属于我们自己的Skin sql server中分页获取数据的存储过程 轻量级的数据库访问类 DotNetNuke:自动升级功能(一) DNN第三方贡献 CodeProject上最近(2004-09-24)发现的几个好代码 使用Reflector工具解决问题 关于Rainbow的一些思考 FreeTextBox的ToolbarButton整理 web的用户验证方式 SqlServer通用存储过程的编写 我将msdn上一篇关于数据库打包的文章由vb改为cs拉,好久没发言了,希望这个东西对大家有用! DotNet(.Net)下构建高适应性的三层架构 DotNetNuke:自动升级功能(序) 关于PagedDataSource,非常好用的一个分页属性! IronPython的第一块鳞片 关于Rainbow的一些思考 柱状图改进版 CN.Text开发笔记—利用反射将数据读入实体类 布局和配色(Rainbow的Design目录) 存储过程编写经验三 存储过程经验二 扩展AdRotator控件,让它支持.SWF广告 (源码) 描述 Machine.Config 和 Web.Config(转载) sqlserver 海量数据导入的最快方法 Community 学习(C#版) DataGrid使用<2> 绑定checkbox [百万级]通用存储过程.分页存储过程. 实现千万级数据的分页显示! 今天把最近看DotNetNuke的心得写一些,希望对别人有所帮助 DNN(DotNetNuke)研究手札系列2-背景、现状 win2003优化大全 (转载) DNN(DotNetNuke)研究手札系列1-资源 DotNetNuke 2.1.2安装指南 DataGrid资料 DataGrid技巧大集合  asp.net速查手册 GridView/DataGrid单元格不换行的问题 如何在GridView中使用DataFromatString VS2005新控件之GridView 使用高级技巧系列[一][视频] VS2005新控件之GridView 使用高级技巧 几个.Net开源的CMS、Portal系统 gridview中加弹出窗口用例 GridView&DetailsView对XML文件增删改 [译]Scott Mitchell 的ASP.NET 2.0数据教程之十一: 基于数据的自定义格式化 初谈ADO.NET中利用DataAdapter进行数据操作 单一登录 Web 应用程序的企业级安全系统 发布XenoCode 2006 for DotNet 2.0破解程序 IBatisNet+Castle构架开发指南 IBatisNet+Castle构架开发指南 (续) 附代码生成模板 GridView根据值的变化改变行列样式 使用ASP.NET 2.0中的GridView控件 我积累的数据库操作类(ASP.NET) 我积累的数据库操作类(ASP.NET) 我积累的数据库操作类(ASP.NET) GridView 控件编程的事件 css+div布局总结--新手入门 15分钟内快速构建数据访问层(翻译) Transact_SQL小手册(各种sql语句大集合) Exports datatable to CSV or Excel format [转贴]开发VS2005下ComboBoxTreeView(下拉列表框弹出树) 与ToolStripComboBoxTreeView(下拉列表框工具条弹出树) 使用配制文件定制身份验证和基于角色的安全 一句SQL得出表中重复的数据(TMP) SQL精妙语句 Asp.net2.0:如何使用ObjectDataSource(配合ORM) Sql Server数据库的备份和恢复措施 SQL Server2000数据库文件损坏时如何恢复 存储过程编写经验和优化措施 (转) 征集佳句-精妙SQL语句收集 利用WebBrowser彻底解决Web打印问题 各种sql语句大集合 自定义用户访问权限 DataGrid导出excel和word的例子 具有滚动条的div SQL Server 2005 Express 附加的数据库为“只读”的解决方法 Sql 导入/导出Excel 不走寻常路 设计ASP.NET应用程序的七大绝招 ASP.NET性能优化 ASP.NET性能优化 对数据库Sql Server常用操作类库SQLHelper 如何取出treeview中checkbox的值 海量数据库的查询优化及分页算法方案 使用配制文件定制身份验证和基于角色的安全 VS2005新控件之GridView 使用高级技巧系列[二][视频] 一条经典的汇总的sql sql Server 索引优化 (转) Log4Net使用指南 一些有用的sql语句实例 Enterprise Library 2.0 -- Data Access Application Block 在Excel中将连续多列相同数据项合并 执行SQL存储过程事事例 SQL宝典 SQL语句导入导出大全(轉,收藏用) gridview中手工排序 Asp.net 项目中引入Nhibernate 入门(一) 利用asp.net 2.0的客户端回调功能制作下拉框无限级联动 给大家推荐一个我的开源项目: Permission Base 一个 NHIBERNATE+GRIDVIEW 添加删除修改的例子(单表) IBatisNet基础组件 用javascript将数字转换为中文大写 asp.net的TextBox回车触发事件 利用Sql作业在asp.net 里面实现异步调用存储过程. 抓取Web网页数据分析 VS2005中如何动态设置数据库连接信息? GridView控件修改、删除示例(修改含有DropDownList控件) JavaScript有用的代码,摘抄自:http://bbs.tech.163.com/board/rep.jsp?b=tech10&i=1296&p=0 [转] 一些sql语句的详细解释 DataGrid使用心得(附大量代码) [转] SQL Server中各个系统表的作用 使用 Web Services Enhancements 2.0 的基于角色的安全性 Flash+asp.net打造FLASH首页新闻发布 SQL存储过程事务和优化方法(包括查询方式语句结合) 小记存储过程中经常用到的本周,本月,本年函数 GridView Css ASP.NET 2.0 Language Swithcer and Theme Swiche ASP.net2.0学习资料汇总 触发器与约束的适用条件 GRIDVIEW 中当数据行数未满时,填充空白行 ComponentArt Web.UI for ASP.NET 2.X序列号 创建用于监视对student表进行插入和更新操作的触发器 20060516: 实现圆角div效果 .net绝对技术资料 sql server2000中使用convert来取得datetime数据类型样式(全) 一些sql 语句(行列转换等) [转载] Owc的使用---自己封装好的类可以实现14种分析图 非常經典的WEB列印方案 CuteEditor 5.0 的使用 ASP.NET 2.0构建动态导航的Web应用程序(TreeView和Menu ) MD5算法的T-SQL实现 ASP.NET2.0中数据源控件之异步数据访问 DotNetGrid 控件下载 DotNetGrid 介绍 WEB打印-------我的搜集 在校生数据导入范例 关于多极分类的几个存储过程 一个 NHIBERNATE+GRIDVIEW 添加删除修改的例子(单表) 树形数据查询示例 转 SQL Server 数据库管理常用的SQL和T-SQL语句 IIS状态代码的含义 .NET平台下带权限控制的TreeView控件节点生成算法(转载) 实现HTTP内容的抓取 给SQL Server存储过程,传送数组参数的变通办法 在.net中使用Fckeditor [转] SQL的3种连接查询 海量数据库的查询优化及分页算法方案 [转] transact---sql高级查询(下) [转] transact---sql高级查询(上) SQL Server数据库开发的二十一条军规 Excel编程 存储过程语法 SQL 语法参考手册 ASP.NET之精通弹出窗口 在网页中插入视频播放代码全集 无限级分类的实现 资源名称资源名称取得汉字字符串的拼音首字母的mssql函数 树_ajax 树_ajax GridView与DataGrid中的数据项访问差别 Gridview中onmouseover的效果 ASP.NET2.0+SQL Server2005构建多层应用(转载) 修正过的通用分页存储过程 [推荐]网络上通用的调查答卷系统-XML做数据库(将DataSet转化成字符串) MS-SQL数据库开发常用汇总 在visualStudio里面使用SqlServer2000作为数据源 获取影响行数和ID的存储过程 C# .Net中的类型转换 C#.net常用函数 SQL注入 FCKeditor2.2+ASP.NET2.0不完全攻略 FCKeditor2.2+ASP.NET2.0不完全攻略 【转贴】datagrid数据导出到excel文件给客户端下载的几种方法 GridView动态生成模板列 关于树形控件 asp.net 备份和恢复SQL SERVER 数据库 Asp.net(C#)实现验证码功能 Asp.NET程序中常用的三十三种代码 分割以逗号作为分割符号的字符串并插入到表中 列出一个表中的某个字段重复的记录 DataGrid系列技巧(导出excel,事件,多种方式呈现数据,全选全删)等等等 把以"文本文件(制表符分割)"保存的EXCEL文件导进SQLSERVER2000的DEMO! 总结:ADO.NET在开发中的部分使用方法和技巧 (转贴) DATAGRID的全选/取消全选控制(CHECKBOX) 使用SqlBulkCopy类加载其他源数据到SQL表 使用SqlBulkCopy类加载其他源数据到SQL表 使用SqlBulkCopy类加载其他源数据到SQL表 一个调查实例<主要训练向panel中添加控件>包括全部代码 ASP.NET 2.0客户端回调的实现分析(3)[ZT] [原创]把SQL的动态查询改成SQL查询 SQL Server实用经验技巧集 使用 DataAdapter 执行批量更新 treeview的建立,更新,删除 C#实现web信息自动抓取 [收藏].net关于企业Excel报表的生成 将 ASP.NET 2.0 应用程序服务配置为使用 SQL Server 2000 或 SQL Server 2005(转) .NET进销存系统开发笔记------之Gridview应用 .net 2.0中GridView无限级嵌套的实现 导入Excel电子表格数据到SQLSever数据库的另一种方法 一个购物车的简单实现(多层开发) ASP.NET2.0中 TreeView 和ORACLE 数据绑定的一种方法 ASP.NET2.0 ObjectDataSource的使用详解(2) ASP.NET2.0 ObjectDataSource的使用详解(1) 将DataSet更新自动提交到数据库工具类实现 超强扩展性的DNN-DotNetNuke模块功能分类列表(from 中国DNN) 世界上主要的一些搜索引擎 SQL Server 数据库管理常用的SQL和T-SQL语句 Transact SQL 常用语句以及函数[个人推荐] Survey Admin 示例:实现 Microsoft .NET 基于角色的安全性(转) NHibernate Step by Step (四)Session、Query及HQL NHibernate Step by Step (三) Configuration和Sessionfactory Microsoft .NET Pet Shop 4 架构与技术分析 PetShop的系统架构设计 Asp.Net 2.0 TreeView的Checkbox级联操作 无废话-SQL Server 2005新功能(1) - TSQL 导出导入Excel(DataSet,DataGrid) DNN开发中的一些细节(1) DNN开发中的一些细节(2) ASP.NET2.0: Ilungasoft.Framework.Web之基于Callback的无刷新上传进度条控件[带源码] TreeView 爱恨之间 Transact SQL 常用语句以及函数 Transact SQL 常用语句以及函数 ASP.NET 2.0 正式版中无刷新页面的开发 DNN开发中的一些细节(1) ASP.NET2.0快速入门--高级数据方案(3) 结合CodeSmith开发和调试DNN3模块 SqlDataSource WEB控件:当DeleteCommandType="storedProcedure"时 关于TreeView控件专题 利用Treeview做权限树的一种方法 利用Treeview做权限树的一种方法 (新)在ASP.NET中调用存储过程传参数 ASP.NET2.0快速入门系列--高级数据方案(上) ASP.NET2.0快速入门--高级数据方案(中) asp/asp.net中遍历树型结构. ASP.NET 2.0中使用multiview控件 ASP.NET2.0快速入门系列--高级数据方案(上) DataGrid,GridView和DetailsView中添加删除确认提示 VS2005中用Code Snippets提高开发效率 IIS和ASP.NET2.0 关于vs 2005的一个问题, 解决The path "xxxx' maps to a directory outside this application, which is not supported. VS2005第一天 Failed to access IIS metabase 无ASPX文件部署(续) ASP.NET 2.0构建动态导航的Web应用程序(TreeView和Menu ) ASP.NET 2.0基于SQLSERVER 2005的aspnetdb.mdf部署 对vs2005生成dll文件的一点疑惑 ASP.NET 2.0 新特性 WEB Service 下实现大数据量的传输 switch your web application project to use development machine's IIS server [ASP.NET 2.0 Security FAQs]如何设置SQL Server或SQL Express数据库,使其支持Membership、Profiles和Role 将 ASP.NET 2.0 应用程序服务配置为使用 SQL Server 2000 或 SQL Server 2005(转载) GridView 控件使用不完全指南! 【原创】asp/asp.net中遍历树型结构. .NET Pet Shop 4.0案例研究预览篇 关于树形结构的研究的资料收集 单点登录(SSO)的核心--kerberos身份认证协议技术参考(三) Gridview:在进入编辑模式后动态添加控件 ASP.NET中大结果集的分页[翻译] Asp.Net Forums研究文章集合(收藏) ASP.NET2.0中Gridview中数据操作技巧 SQL Server中利用存储过程来高性能地进行分页 关于二级域名Cookie的问题及解决方法 一步一步建网-2-DotNetNuke4-5/6-杂项/感! 通过系统配置来提高ASP.NET应用程序的稳定性 GridView 控件使用不完全指南!(续一) ASP.NET应用程序的部署--兼谈aspnet_compiler.exe命令 RDLC报表(一) RDLC报表(七) GridView 控件使用不完全指南! DNN皮肤制作 一个登陆页面,包含了初始化用户,输入检测,错误处理等 DNN皮肤制作 基于dotnetnuke的网站全新上线! [导入]DotNetNuke Skin 與 Container 設計介紹 CodeSmith3.0开发资料下载 CodeSmith开发系列资料总结 提高SQL执行性能方案:如何让你的SQL运行得更快zt Visual Studio 2005 的101个示例下载 网络数据库挖掘程序的设计 对联广告代码效果大全 网站生成静态页面,及网站数据采集的攻、防原理和策略 [原创]终极防范SQL注入漏洞! 【先锋海盗类】Ver2005 完美版 拿别人的新闻来用,虽然我知道这样不好,还是用了。。。 网页小偷程序ASP.net 数据采集程序(网页小偷)点滴心得 部署安装时写入SQL SERVER和Web.config 将博客园程序从Visual Studio 2003迁移到Visual Studio 2005的尝试 开篇:Nhibernat.Test项目分析之:ConfigurationTest 基于NHibernate的三层结构应用程序开发初步 15分钟内快速构建数据访问层(翻译) Asp.net 2.0专题二:本地化(Localization) 数据库应用基础系列 深入了解 SQL Server 2000 与 ADO.NET 中的事务隔离及数据锁定 第2章 并发操作的一致性问题 (2) 在asp.net 2.0中使用SqlBulkCopy类迁移数据 使用asp.net 2.0和SQL SERVER 2005构建多层应用 推荐个关于 team system教学的好站点 推荐个关于 team system教学的好站点 DataList控件也玩分页- - SQL Server 两个触发器例子,大家看看怎么样? 发布一个原创的基于Ajax的通用(组合)查询(续) 在IIS6.0下ASP .NET 的版本冲突问题 FCKeditor应用小记--起步篇 WEB Service 下实现大数据量的传输 菜单控件 55种网页常用小技巧(转载) [转]Microsoft PetShop 3.0 [转载]用WSE在Web服务中验证用户身份 一次SQL Server 2000修复实践的说明 新数据网格DataGridView简介(转自MSDN) [转贴]Visual Studio 2005常用插件搜罗 第 4 章 构建以数据为中心的应用程序 网 站 策 划 [转载] 在.net安装程序部署SQL Server数据库 [转载] 在.net安装程序部署SQL Server数据库 ASP.NET程序中常用代码汇总(一)(转载) ASP.NET程序中常用代码汇总(二)(转载) ASP.NET程序中常用代码汇总(三)(转载) ASP.NET程序中常用代码汇总(四)(转载) ASP.NET程序中常用代码汇总(五)(转载) 露雨资源库(第一个.net2.0软件)二 ADO.NET 2.0 大批量数据操作和多个动态的结果集   本文转自钢钢博客园博客,原文链接:http://www.cnblogs.com/xugang/archive/2008/01/20/1045957.html,如需转载请自行联系原作者
文章
SQL  ·  Web App开发  ·  .NET  ·  C#  ·  数据库
2017-11-26
OEA ORM中的分页支持
 本篇博客主要描述分页的常见技术方案,以及在 OEA 框架中的分页的应用及实现原理。   分页的几种方案     分页是解决大数据量显示的有效方法。根据分页技术应用的位置不同,大致可以把分页分为以下几种: 界面层分页      界面层的分页,类似于界面的虚拟化技术,是只显示需要的数据的一种技术。OEA 的 WPF 界面中目前已经实现了 UI 虚拟化,所以不再实现界面层分页。 优点: * 简单。许多控件都支持在界面层直接进行分页。 * 换页时,响应快。(在 C/S 结构下使用这种方案,数据都已经到达客户端,所以在分页时不需要额外的数据查询,响应速度较快。) 缺点: * 不用于太大的数据分页。由于没有减少网络传输,首次加载时较慢,需要把所有数据都传输到客户端。 实体层分页     在实体层进行分页操作的方案,很少会被使用。它是把查询出来的数据,在服务器端都转换为实体,然后再找到具体页的实体数据,其它的数据则直接丢弃。 优点: * 减少了首次的网络传输,对于客户端而言,调用的是分页的 API。 * 简单。 * 通用性强,与数据库无关,方案可以跨多种数据库。 * 统计总行数不需要发起二次查询。 缺点: * 占用内存,依然不能用于太大的数据分页。 数据层分页      这种方案一般使用 IDataReader 实现。查询的 SQL 依然是查询所有的数据,但是在对查询出的 IDataReader 进行遍历读取每一行时,只读取对应页的数据,其它页的数据则忽略。同时,遍历到记录集的最后一行,即可获得数据的总行数。 优点: * 不占用大量内存。只把需要的数据读取到内存中。 * 简单。 * 通用性强,与数据库无关,方案可以跨多种数据库。 * 统计总行数不需要发起二次查询。 缺点: * 查询的 SQL 会查询很大的一张表。遍历依然需要耗费一定的时间。 数据库分页      分页的最终方案,自然是在数据库中进行分页。这也是大多数情况会选用的方案。 优点: * 性能最好。速度快、占用内存小。 * 统计行数时,往往需要重新发起查询。 缺点: * 对于框架开发而言,要生成分页相关的 SQL,较麻烦。 * 方案与特定数据库相关。通用性低。     虽然提到了这几种不同层面的分页方案。但是对应应用开发而言,数据库的分页是最常用的。只是在做 OEA 框架开发时,由于要支持多种数据库,所以需要在合适时采用不同的方案。同时,也不会考虑使用存储过程来辅助分页。 OEA 分页 - 应用层接口     在说明 OEA 的分页前。先介绍一个 PagingInfo 类型(老版本中,该类名为 PagerInfo),这关系到整个分页方案的接口设计: 图1 位于 Common(原 hxy)程序集中的 PagingInfo 类型 图2 PagingInfo 类型接口     在查询数据时,我们指定了查询的具体页码 PageIndex、一页所含数据行数 PageSize,就可以把该页的数据显示在界面上了。但是,在分页时,往往要在界面中显示一个分页脚,用于显示当前页号、所有页数。所以在进行查询的同时,往往还需要对结果集中所有数据的总行数进行统计,并把之与查询出的实体列表数据一同返回。所以,我为 PagingInfo 添加了额外的两个属性,IsNeedCount、TotalCount,当 IsNeedCount 被设置为真时,框架在数据层进行查询时,会把统计出来的总行数赋值给 TotalCount。   OEA 分页 - 使用方法     下面以分页查询所有数据为例,简单说明如何使用分页查询。先是应用层使用的代码: 应用层需要构造 PagingInfo,并指定需要统计行数。查询后,直接使用 PagingInfo.TotalCount。(这种接口方案从 06 年使用至今,比较好用。) 下面是 Repository 类型上的公有接口: 最后,再实现该查询对应的数据层即可: 可以看到,在数据访问层的 ORM 框架中,主要是在 IQuery 条件类型上添加了一个 Paging 方法。使用这个方法指定了 PagingInfo 后,即按给定的分页信息分页查询实体数据了。 OEA 中的数据层分页实现      OEA 中用到的分页有:界面层分页、DataReader 分页、数据库分页。 界面层分页  其实在 OEA 中就是 UI 虚拟化。相关内容,可以查看《OEA 中 WPF 树型表格虚拟化设计方案》 及 《 精通 WPF UI Virtualization》。    数据库分页(分页SQL)     目前,OEA 已经支持了 SqlServer 2005+、Oracle 10+、SqlCE4+,但是框架的设计目标则是应对所有数据库(接下来很可能需要对 MySql 进行支持)。这三种数据库中,OEA 只支持前两种大型数据库的数据库分页,主要是生成分页 SQL 进行查询。     经过对比、挑选,我选用了一种可以在 SqlServer、Oracle 上的一种通用方案,即使用 RowNumber。例如,如果一个 SQL 查询是: select ...... from ...... order by xxxx asc, yyyy desc ,则只需要把它转换为以下格式就行了: select * from (select ......, row_number() over(order by xxxx asc, yyyy desc) _rowNumber from ......) x where x._rowNumber<10 and x._rowNumber>5 。     同时,当需要统计总行数时,数据层会生成 SELECT COUNT(0) FROM ...... 的 SQL 语句重新进行查询,并把结果赋值给 PagingInfo.TotalCount,以及 EntityList.TotalCount。     在 SQLCE 中,并不支持 rowNumber 函数。所以只能考虑使用 NOT IN 的 SQL 方案。其实在OEA中,鉴于实现 NOT IN 方案比较麻烦,所以决定暂时使用 DataReader 完成 SQLCE 的内存分页。   DataReader 内存分页      提供 DataReader 方案主要是简单、同时还能与数据库无关,解决跨库问题。主要逻辑代码如下: /// <summary>  ///使用 IDataReader 的内存分页读取方案。 ///  ///注意!!! /// 此方法中会释放 Reader。外层不能再用 Using。 /// </summary>  /// <param name="reader"></param>  /// <param name="rowReader">每一行数据,会调用此方法进行调取。</param>  /// <param name="pagingInfo">分页信息。如果这个参数不为空,则使用其中描述的分页规则进行内存分页查询。</param> public static void MemoryPaging(IDataReader reader, Action<IDataReader> rowReader, PagingInfo pagingInfo = null)  {      bool isPaging = pagingInfo != null;      bool needCount = isPaging && pagingInfo.IsNeedCount;      int totalCount = 0;      int startRow = 1;//从一开始的行号      int endRow = int.MaxValue;      if (isPaging)      {          startRow = pagingInfo.PageSize * pagingInfo.PageIndex + 1;          endRow = startRow + pagingInfo.PageSize - 1;      }      using (reader)      {          while (reader.Read())          {              totalCount++;              if (totalCount >= startRow)              {                  if (totalCount <= endRow)                  {                      rowReader(reader);                  }                  else                  {                      //如果已经超出该页,而且需要统计行数,则直接快速循环到最后。                      if (needCount)                      {                          while (reader.Read()) { totalCount++; }                          break;                      }                  }              }          }      }      if (needCount)      {          pagingInfo.TotalCount = totalCount;      }  } 通用,又简单。   待改进点 目前实现上,可能存在的缺陷是: 对分页 SQL 的转换不支持复杂的嵌套 SQL。这时可能出错。   本文转自BloodyAngel博客园博客,原文链接:http://www.cnblogs.com/zgynhqf/archive/2013/01/23/2873583.html,如需转载请自行联系原作者
文章
SQL  ·  关系型数据库  ·  C#  ·  数据库  ·  虚拟化
2017-11-16
殊途同归,ado.net快速实现MySql的CRUD
正在学习MySql编程,安装了官方的C#客户端,在自己的机器上写了个demo,将可能常见且容易出现的问题或错误温故知新一遍,写下来以备日后再用。 一、MySql的连接字符串 连接字符串无比简单,但是这是必须的。我们需要关心的是,通过.net客户端程序,mysql的连接字符串可以像sql server一样,利用连接池高效管理连接。简单配置如下: 1 2 3 <connectionStrings>   <add name="MySqlConnString" connectionString="Server =localhost; Database =test; Uid =***; Pwd =***;Pooling=true; Max Pool Size=20;Min Pool Size=10;Allow Batch=true;" providerName="MySql.Data.MySqlClient"/> </connectionStrings> 更多参数,请参考: http://dev.mysql.com/doc/refman/5.6/en/connector-net-connection-options.html http://www.connectionstrings.com/mysql   二、实现简单的CRUD 毫无疑问,快速上手CRUD的前提是必须熟悉基础的sql,然后再对照mysql的特定语法做特定操作。不要小看了这简单的crud,普通应用系统中这部分的工作占了很大一部分,笔者才疏学浅,为这部分工作也花过不少时间。还好我们现在有了各种优秀的orm,相对而言实现起来比较轻松。 1、插入记录 最简单的方式,当然是传入参数一条一条插入: addperson   经测试,插入数据的存储过程里的变量定义可以和列名一模一样。基于mysql的特殊语法,建议参数变量不要和列名一模一样,最好给个别名,这里不是介绍的重点,略过。 和插入记录比较类似的一个功能就是复制表定义及复制数据行,曾经简单总结过,不再赘述。 插入记录还有一个比较常用的功能,就是批量插入。 记得在向Sql Server批量插入的时候,可以通过SqlBulkCopy实现批量快速插入。先使用SqlBulkCopy测试了下MySql的批量插入,执行的结果就是直接如下抛出异常: “在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: Named Pipes Provider, error: 40 - 无法打开到 SQL Server 的连接)” 在配置文件中将连接字符串加上providerName(providerName="MySql.Data.MySqlClient")依然如故。看到这个结果忍不住哀号一句,老子tmd是要向mysql插入数据啊。 无奈打开msdn,看到SqlBulkCopy类的功能介绍直接崩溃:“lets you efficiently bulk load a SQL Server table with data from another source.”。原来SqlBulkCopy只对SQL Server有效啊,这点从它的命名空间(System.Data.SqlClient)大致可以猜到,MS真不厚道。 那么到底怎么实现批量插入的功能呢? 利用ILSpy查看了一下C#客户端的源码,发现有个MySqlBulkLoader,查看示例竟然是从文件中批量操作数据的,这个明显不满足我们的开发要求。话说不就是一次多插入几条数据吗?至于真的要先写入文件吗? 最后在网上搜索了一下,看到iteye上的一篇Java 批量插入数据库(MySQL)数据,仔细分析这篇文章,个人认为Java下实现批量插入无非就是通过JDBC API或者PreparedStatement批处理方式,实现思想还是比较简单的。其实.net也有自己的api实现批量插入(SqlBulkCopy),只是不支持mysql而已;而批处理命令(PreparedStatement)我怎么看上去都像是拼接字符串呢?得知mysql和db2支持下面这种多行插入(multi row insert): insert2persons   我立刻想到实现批量插入的一种简单方式(也就是他的文章里提到的伪批处理命令),需要拼接sql字符串。贴一下有sql注入风险的示例代码: batchinsert1 调用如下: testbatchinsert1   通过上面代码可以看到,拼接字符串的地方没有进行特殊字符串处理,很容易造成sql注入。虽然实际开发的时候可以通过一个字符串处理函数进行sql敏感字符串处理,但显然这不是最优的方式。我们完全可以参数化传参再插入,重新改进代码如下: batchinsert2   调用方式如下: testbatchinsert2   还是免不了拼接,而且可读性较差,参数较多,调用不够简洁。 那如何更好地批量插入呢?老实说,直到现在我也还是不知道。实际开发中,批量插入的方式通常都是按照实体列表进行插入(或者使用datatable批量插入)的。于是,我又重写了一个泛型方法,用来实现参数化的批量插入,当然,原理还是拼接字符串,对于常见数据库批量插入操作,我推荐你使用下面这种方式: BATCHINSERT 调用方式也比较简洁,如下所示: TestBatchInsertModels   经测试,构造插入字符串的地方,参数前面必须加个“@”符号,如果不加,则抛出异常,这一点很奇怪。 必须指出,sql拼接执行插入的长度是有限制的。在我的电脑上测试插入3000个实体一点问题没有,当插入1万条记录的时候也还行,当插入10万条的时候……虽然我没有测试过可以执行的sql长度最长是多少,但是根据经验,这个sql总长度应该不会超过8k+的长度限制吧(存疑??),所以开发中可以按照策略对需要批量操作的数据再分批量插入。 如果您有好的批量插入数据的思路和解决方案,请不吝赐教。   2、查询 数据库的两大作用,一个是存储,另一个就是各种查询了。所以必须重视查询,重视查询的形式当然是从熟悉查询语法开始,这里不做过分说明,大家可以参考官方说明文档。 简单查询如利用组合条件或者id主键查询记录,很简单: querypersons   在程序中调用非常简单,正确传参即可: querypersons   注:mysql的字符串函数不同于sql server,最简单的字符串连接,mysql通常都是通过CONCAT函数,而sql server则用+号即可。 CONCAT函数在mysql编程中出现频率极高,它的用法如下: 1 CONCAT(str1,str2,…) 连接的字符串参数个数看上去原则上是无限制的,返回结果为连接参数产生的字符串。 它还有两个特性,记录一下: (1)、如有任何一个参数为NULL ,则返回值为 NULL。 1 2 3 mysql> SELECT CONCAT('My', NULL, 'Sql');   -> NULL (2)、CONCAT一个或多个参数,如果所有参数均为非二进制字符串,则结果为非二进制字符串;如果自变量中含有任一二进制字符串,则结果为一个二进制字符串。一个数字参数被转化为与之相等的二进制字符串格式。 1 2 3 mysql> SELECT CONCAT('My', 'Sql',2011);   -> BLOB 下面重点讨论一下分页查询的实现: mysql的取前top n条记录有自己的语法,即limit n,这个在这一篇里曾经提及。limit还有一个偏移区间的写法:limit offset,n,第一个参数offset指定第一个返回记录行的偏移量,第二个参数n指定返回记录行的最大数目,举例来说: 1 mysql> SELECT * FROM table LIMIT 5,10;  // 检索记录行 6-15 还有一种方式就是指定第二个数字n为-1,那么它表示的意思就是查询从某一个偏移量到记录集结束的所有记录数: 1 mysql> SELECT * FROM table LIMIT 5,-1; // 检索记录行 6-last. 这种特性相当适合分页。关于分页,技术社区和论坛里讨论的非常多,下面就再简单说说利用mysql的limit的特性按照主键ID逆序分页取记录的功能实现。常见的分页处理方式是通过如下这种分页存储过程: getpagerperson1   我们稍微分析一下就可以发现,对于数据量较大的查询,越往后面效率应该越低,因为越往后检索的记录行越多,这一点在高效的MySql分页介绍里已经得到验证。 和传入当前页码和每页记录数类似的是传入开始记录和结束记录这种方式,本质上和上面是没有区别的: getpagerperson2   真正可以高效的查询,当然是记住上一次查询结果的最小(或者最大)主键,这取决于查询是逆序还是升序排序。像下面这样实现的查询越往后翻页则可以省却查询很多记录行: quickpagergetpersons 也就是说对于>1以后的查询都需要记住上次查询的一个“临界值”(通常情况下:如按Id逆序,最小Id;按照Id降序,最大Id)。园子里流传甚广的一篇博客高效的MySql分页讲的也是这个原理。记得早就有很多人总结过sql server下的分页方式,其中经典的二次top我感觉和limit的方式非常相似,只不过limit的效率可能更高一些。 注:在存储过程中LIMIT后面只能是常量而不能是变量,所以只好用字符串拼接生成SQL语句,然后动态执行即可。 【UPDATE】:经同事提醒,是MySql版本问题,本地的测试环境是MySql5.0,换成MySql5.5,MySql引擎已支持LIMIT后面使用变量。 同时还要切记,分页查询尽量按照主键正序或者逆序查询,否则按其他有可能重复的字段分页,查询的结果可能不准确(想想为什么?),实际开发经验中这一点已经得到了验证。 最后不能免俗,重新发布一个mysql通用分页存储过程,类似于sql server下的通用分页存储过程,核心思想当然是动态拼接字符串: sp_pager   调用方式如下: 1 CALL test.sp_Pager(2,10,'Id,FirstName,LastName,CreateDate,UpdateDate,State','test.Person','ORDER BY ID DESC'); 3、修改 通常情况下,按照主键修改一条记录信息相对而言比较简单,只要sql正确、传参无误,功能实现基本和sql server一模一样。 有时候我们需要进行跨表多数据量更新,比如sql server下可以通过update from的方式进行两张表或多张表数据更新,在mysql下如何实现update from方式的更新呢? 举例:有两张表Person和People,表结构完全一样。现在要实现sql server如下的功能: updatefrom   对于sql server再简单不过的功能,mysql下需要稍微绕点弯, mysqlupdatefrom   虽然看上去也还算简单,可是毕竟需要join查询。而对于数据量较大的表,我曾经得到过的一个重大教训就是减少连接查询。 关于修改的功能,还有一个地方需要注意,就是在原来对应列的数据基础上更新数据,比如将所有人的Age都更新为原来的数据加1,备注修改为全名: 1 UPDATE test.Person SET Age=Age+1,Remark=CONCAT(FirstName,LastName); 上面的sql语句执行是没有问题的。除非需要更新的列指定不明,执行的时候,sql编辑器会给出警告: Column '***' in field list is ambiguous。这就说明某一列指代不明。   4、删除 删除的功能和sql server非常相似,一条一条删除(DELETE FROM *** WHERE ***)无疑是最基础最常用的,这里不做示例展示。 和删除相关的就是清空表数据,sql server下的TRUNCATE TABLE *** 对mysql同样适用。 下面着重介绍删除重复记录的实现。 在sql server下,我们需要删除某列的重复记录(示例是FirstName相同,保留的列是ID最小的记录)很简单: deleteduplicate ps:要找出表中某个字段的重复值,记得曾经在这篇随笔里提及过。原理就是count+分组: select 字段名,count(字段名) from 表名 group by 字段名 having count(字段名)>1 如果将上面的sql语句放在mysql下面执行,会给出错误警告:Error Code: 1093. You can't specify target table 'Person' for update in FROM clause。 同样的功能,在mysql里的实现如下: mysqldeleteduplicate   感觉mysql的这种写法比较迂回一点,好坏不做评价。   三、需要注意的几点 1、插入的记录不合法 在插入的时候,比如插入FirstName的值超过了varchar(16)的长度,则抛出mysqlexception,并提示:Data too long for column 'FirstName' at row 1。这点类似于sql server下的二进制字节流截断的异常。   2、mysql语句的参数传递 经测试,在mysql的存储过程中传递一个和列名Id完全一样的叫Id的参数是相当危险的。在我的测试中,删除存储过程DeletePerson如下: DeletePerson   获取一条的存储过程如下: GetPersonByID   更新一条记录的存储过程如下: updateperson   但是执行的效果远不是期望的那样,真正的效果依次是删除所有记录、选取出所有记录和更新所有记录。这样很容易造成误删除或者误读取或者错误更新。解决的方法相当简单,给参数起个不是Id的别名即可。 那么通过sql语句而不是存储过程实现增删改查的参数传递如何呢? 我们不妨以update方法一试: updateperson   实际效果果然非常诡异。 这里我大胆推测,官方提供的MySql 的C#客户端沿袭了Sql Server下的某些写法,所以,直接执行sql语句的时候,建议传递的参数必须带上“@”符号(经本地测试,增删改查都可以这么写;虽然@在存储过程里是个敏感字符,但是c#程序里调用存储过程传参也是可以使用@符号的),这个和前面拼接sql批量插入的地方有某种程度的巧合,而实际上人家可能就是这么设计传参的。 PS:我的一个牛人同事告诉我mysql存储过程传参的一些基本用法,其中着重强调的就是参数传递尽量按照mysql的标准来写,而不要沿袭sql server的写法,否则可能会造成不小困扰。他有非常丰富的开发经历,虽为经验之谈,经测试验证果然非常正确,今后必须汲取。   3、mysql的特殊语法和函数 我们知道,主流关系型数据库有多种,它们都有各自的特点和适用环境。所以如果一个人哪怕是多么了不起的dba,他也不太可能轻易地将各个平台的数据库知识都了然如胸。从这个层面来讲,学习通用而基础的sql原理和知识显得尤为重要,CSDN和博客园有很多优秀文章值得细细品读和学习。 对于像我一样的新手,我认为学好基础的sql,再深入熟练使用不同厂商的特殊语法和内置函数方能游刃有余,mysql的特殊语法和函数当然是一个重要的补充。这几天学到了不少mysql的“独特”写法,这里说它独特,主要还是先入为主,毕竟我个人使用sql server的开发经验远远高于mysql。准备将mysql和sql server的一些常见用法做个对比,这里不再一一列举。   四、打造自己的简易ORM 在之前介绍ado.net的几篇文章中,自己动手实现了一些类似orm的帮助类库(曾经改进了几次,但是不太令人满意),针对sql server的实现相对比较简单,而对mysql和oracle的一直没有动手。在文章最后的下载demo中,我参考了sql server的风格封又重新实现封装了个MySqlHelper(不是官方的那个MySqlHelper),感觉还不错。精力有限,有时间我可能也会把mysql的功能和sqlserver的实现整合在一起,当然还是等用熟了MySql再动手。 最后,求推荐一款简单易用的针对MySQL的ORM。    本文转自JeffWong博客园博客,原文链接:http://www.cnblogs.com/jeffwongishandsome/archive/2011/09/13/2173696.html,如需转载请自行联系原作者
文章
SQL  ·  关系型数据库  ·  MySQL  ·  测试技术  ·  C#
2017-11-21
Winform开发框架之存储过程的支持--存储过程的实现和演化提炼(2)
本篇继续上篇《Winform开发框架之存储过程的支持--存储过程的实现和演化提炼(1)》来对Winform开发框架之存储过程的支持进行介绍,上篇主要介绍了SQLServer和Oracle两种数据库对常规存储过程的编写和对比,本篇主要介绍如何在C#里面,如何对这些存储过程进行调用,并获取到对应的数据类型,如输出参数,单个数据记录,多个数据记录等情况。最后在完成实现功能的基础上,对这些实现进行演化提炼,并扩展到我的WInform开发框架里面,实现功能重用、代码简化的目的。 1、数据访问接口的定义 我们整个实例是以一个客户表T_Customer为例进行讲解的,整个表的框架支持代码,可以通过代码生成工具进行快速生成,生成后包括了IDAL、Entity、DALSQL、BLL层代码,然后可以利用代码进行测试存储过程是否执行成功等功能。 数据访问层的定义,依照框架的分层模式来处理,后面我们在增加DALOracle对Oracle数据库进行支持即可。 生成后数据访问层接口,他们通过基类接口继承的方式,已经具有了常规的增删改查、分页等系列接口,但是其他业务接口还是需要自己定义的,如数据访问接口成的定义如下所示。 namespace WHC.TestProject.IDAL { /// <summary> /// 客户信息 /// </summary> public interface ICustomer : IBaseDAL<CustomerInfo> { } } 这里面的代码很简单,没有多余的代码行,那么里面究竟发生了什么呢,其中的IBaseDAL又是什么定义呢? 其实,IBaseDAL就是定义了很多我们开发用到的基础接口,如标准的增删改查,以及衍生出来的一些其他接口,如分页查询,条件查询等接口内容。这个ICustomer就是用来定义一些除了标准接口不能实现外的业务接口。 如果我们需要实现基于存储过程的接口,我们可能就需要增加一些接口定义,如下所示。 namespace WHC.TestProject.IDAL { /// <summary> /// 客户信息 /// </summary> public interface ICustomer : IBaseDAL<CustomerInfo> { #region 使用存储过程 /// <summary> /// 使用存储过程插入数据 /// </summary> /// <param name="info">实体对象</param> /// <returns></returns> bool StorePorc_Insert(CustomerInfo info, DbTransaction trans = null); /// <summary> /// 使用存储过程更新数据 /// </summary> /// <param name="info">实体对象</param> /// <returns></returns> bool StorePorc_Update(CustomerInfo info, DbTransaction trans = null); /// <summary> /// 使用存储过程获取所有数据 /// </summary> /// <returns></returns> List<CustomerInfo> StorePorc_GetAll(DbTransaction trans = null); /// <summary> /// 使用存储过程获取所有数据 /// </summary> /// <returns></returns> DataTable StorePorc_GetAllToDataTable(DbTransaction trans = null); /// <summary> /// 使用存储过程,根据ID获取对应记录 /// </summary> /// <param name="ID"></param> /// <returns></returns> CustomerInfo StorePorc_FindByID(string ID, DbTransaction trans = null); /// <summary> /// 使用存储过程,判断记录ID是否存在 /// </summary> /// <param name="ID">记录ID</param> /// <returns></returns> bool StorePorc_ExistByID(string ID, DbTransaction trans = null); /// <summary> /// 使用存储过程,根据ID删除对应记录 /// </summary> /// <param name="ID">记录ID</param> /// <returns></returns> bool StorePorc_DeleteByID(string ID, DbTransaction trans = null); /// <summary> /// 获取客户的最大年龄 /// </summary> /// <returns></returns> int StorePorc_GetMaxAge(); #endregion } 对于插入、更新和删除这样的操作,我们只需要返回它是否成功就可以了,那么它的接口实现应该是如何的呢? 2、SqlServer存储过程的调用实现 由于我们的Winform开发框架底层是利用微软企业库EnterpriseLibrary来访问数据的,那么对应这个企业库的使用存储过程的方法,也就是我们的实现了。 下面的代码就是它们对应的SqlServer实现了。 public bool StorePorc_Insert(CustomerInfo info, DbTransaction trans = null) { string procName = "T_Customer_Insert"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddInParameter(command, "@ID", DbType.String, info.ID); db.AddInParameter(command, "@Name", DbType.String, info.Name); db.AddInParameter(command, "@Age", DbType.Int32, info.Age); bool result = false; if (trans != null) { result = db.ExecuteNonQuery(command, trans) > 0; } else { result = db.ExecuteNonQuery(command) > 0; } return result; } public bool StorePorc_Update(CustomerInfo info, DbTransaction trans = null) { string procName = "T_Customer_UpdateByID"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddInParameter(command, "@ID", DbType.String, info.ID); db.AddInParameter(command, "@Name", DbType.String, info.Name); db.AddInParameter(command, "@Age", DbType.Int32, info.Age); bool result = false; if (trans != null) { result = db.ExecuteNonQuery(command, trans) > 0; } else { result = db.ExecuteNonQuery(command) > 0; } return result; } public bool StorePorc_DeleteByID(string ID, DbTransaction trans = null) { string procName = "T_Customer_DeleteByID"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddInParameter(command, "@ID", DbType.String, ID); bool result = false; if (trans != null) { result = db.ExecuteNonQuery(command, trans) > 0; } else { result = db.ExecuteNonQuery(command) > 0; } return result; } 对于有返回输出参数的值,我们的做法有些不同,不过最主要的还是最终获取它的输出参数值而已,代码如下所示。 public bool StorePorc_ExistByID(string ID, DbTransaction trans = null) { bool result = false; string procName = "T_Customer_ExistByID"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddInParameter(command, "@ID", DbType.String, ID); db.AddOutParameter(command, "@Exist", DbType.Int32, 0);//输出参数 if (trans != null) { db.ExecuteNonQuery(command, trans); } else { db.ExecuteNonQuery(command); } int iExist = 0; int.TryParse(db.GetParameterValue(command, "@Exist").ToString(), out iExist); result = iExist > 0; return result; } public int StorePorc_GetMaxAge() { string procName = "T_Customer_MaxAge"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddOutParameter(command, "@MaxAge", DbType.Int32, 0);//输出参数 db.ExecuteNonQuery(command); int maxAge = 0; int.TryParse(db.GetParameterValue(command, "@MaxAge").ToString(), out maxAge); return maxAge; } 上面的代码,主要就是利用了AddOutParameter对输出参数的信息进行设置,输出参数的数据类型要和脚本里面的类型定义对应,它的AddOutParameter的size参数值,可以为0。 最后我们通过db.GetParameterValue(command, "@MaxAge")的方式获取它的输出参数的值,并返回即可。 最后一个例子是介绍如何通过代码调用,获得它的实体对象或者实体对象列表,以及DataTable集合对象的例子了,这个也相对不是很麻烦,参照框架里面的做法即可。 获取实体对象信息的代码如下所示。 public CustomerInfo StorePorc_FindByID(string ID, DbTransaction trans = null) { string procName = "T_Customer_SelectByID"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddInParameter(command, "@ID", DbType.String, ID); CustomerInfo entity = null; if (trans != null) { using (IDataReader dr = db.ExecuteReader(command, trans)) { if (dr.Read()) { entity = DataReaderToEntity(dr); } } } else { using (IDataReader dr = db.ExecuteReader(command)) { if (dr.Read()) { entity = DataReaderToEntity(dr); } } } return entity; } 获取集合的代码如下所示。 public List<CustomerInfo> StorePorc_GetAll(DbTransaction trans = null) { string procName = "T_Customer_SelectAll"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); List<CustomerInfo> list = new List<CustomerInfo>(); CustomerInfo entity = null; if (trans != null) { using (IDataReader dr = db.ExecuteReader(command, trans)) { while (dr.Read()) { entity = DataReaderToEntity(dr); list.Add(entity); } } } else { using (IDataReader dr = db.ExecuteReader(command)) { while (dr.Read()) { entity = DataReaderToEntity(dr); list.Add(entity); } } } return list; } public DataTable StorePorc_GetAllToDataTable(DbTransaction trans = null) { string procName = "T_Customer_SelectAll"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); DataTable dt = null; if (trans != null) { dt = db.ExecuteDataSet(command, trans).Tables[0]; } else { dt = db.ExecuteDataSet(command).Tables[0]; } return dt; } 3、Oracle存储过程的调用实现 上面是基于SqlServer存储过程的调用,前面的一篇文章我们介绍了存储过程的Oracle定义,是增加了一个游标来进行记录行数据的处理的,不管对于单行记录,还是多行记录,都是用了游标的输出参数的,那么在客户端里面,使用EnterpriseLibrary,应该如何调用,并且不需要传入这个输出参数的呢,做法其实很类似,只是有一点差异而已。 我们先从最简单的Oracle存储过程调用案例开始,介绍如何调用插入、更新和删除操作的Oracle存储过程的调用。这里和SqlServer的类似,不同的是我们使用了p_前缀来定义参数(基于Oracle的通用脚本参数定义规则)。 public bool StorePorc_Insert(CustomerInfo info, DbTransaction trans = null) { string procName = "T_Customer_Insert"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddInParameter(command, "p_ID", DbType.String, info.ID); db.AddInParameter(command, "p_Name", DbType.String, info.Name); db.AddInParameter(command, "p_Age", DbType.Int32, info.Age); bool result = false; if (trans != null) { result = db.ExecuteNonQuery(command, trans) > 0; } else { result = db.ExecuteNonQuery(command) > 0; } return result; }public bool StorePorc_Update(CustomerInfo info, DbTransaction trans = null) { string procName = "T_Customer_UpdateByID"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddInParameter(command, "p_ID", DbType.String, info.ID); db.AddInParameter(command, "p_Name", DbType.String, info.Name); db.AddInParameter(command, "p_Age", DbType.Int32, info.Age); bool result = false; if (trans != null) { result = db.ExecuteNonQuery(command, trans) > 0; } else { result = db.ExecuteNonQuery(command) > 0; } return result; } Oracle输出外部参数的做法也和sqlServer类似,具体调用代码如下所示。 public int StorePorc_GetMaxAge() { string procName = "T_Customer_MaxAge"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddOutParameter(command, "p_MaxAge", DbType.Int32, 0);//输出参数 db.ExecuteNonQuery(command); int maxAge = 0; int.TryParse(db.GetParameterValue(command, "p_MaxAge").ToString(), out maxAge); return maxAge; } 其他的也就很类似,就不再一一赘述了,基本上和SqlServer的一致,我们节省篇幅,用来看看如何调用返回记录的查询接口。下面是对应的Oracle存储过程的调用代码 public CustomerInfo StorePorc_FindByID(string ID, DbTransaction trans = null) { string procName = "T_Customer_SelectByID"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); db.AddInParameter(command, "p_ID", DbType.String, ID); CustomerInfo entity = null; if (trans != null) { using (IDataReader dr = db.ExecuteReader(command, trans)) { if (dr.Read()) { entity = DataReaderToEntity(dr); } } } else { using (IDataReader dr = db.ExecuteReader(command)) { if (dr.Read()) { entity = DataReaderToEntity(dr); } } } return entity; } 返回多条记录的操作代码如下所示。 public List<CustomerInfo> StorePorc_GetAll(DbTransaction trans = null) { string procName = "T_Customer_SelectAll"; Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(procName); List<CustomerInfo> list = new List<CustomerInfo>(); CustomerInfo entity = null; if (trans != null) { using (IDataReader dr = db.ExecuteReader(command, trans)) { while (dr.Read()) { entity = DataReaderToEntity(dr); list.Add(entity); } } } else { using (IDataReader dr = db.ExecuteReader(command)) { while (dr.Read()) { entity = DataReaderToEntity(dr); list.Add(entity); } } } return list; } 看完上面两个对记录处理的接口,我们看到,还是对我们在Oracle存储过程里面定义的输出游标参数忽略处理,我们不需要对它进行传值,它好像是透明的,呵呵。 这样它的做法就和SqlServer个各个接口实现也都差不多的了。 下面的脚本是我们之前定义的Oracle存储过程脚本,方便对比参照一下调用的函数代码。 ------------------------------------ --作者:伍华聪 http://wuhuacong.cnblogs.com --创建时间:2014年11月27日 --功能描述:以字段ID为关键字,检索表中的数据 ------------------------------------ Create Or Replace Procedure T_Customer_SelectByID ( cur_OUT OUT MyCURSOR.cur_OUT , p_ID IN T_CUSTOMER.ID%TYPE ) AS Begin OPEN cur_OUT FOR Select * from T_CUSTOMER Where ID = p_ID ; End; / 4、业务逻辑层的实现 上面我们定义了数据访问接口,以及两种数据实现层,在框架里面会根据不同的数据库类型配置,然后从不同的数据库访问层构建对象的,业务逻辑层主要就是对他们的接口进行调用了,具体代码如下所示。 /// <summary> /// 客户信息 /// </summary> public class Customer : BaseBLL<CustomerInfo> { public Customer() : base() { base.Init(this.GetType().FullName, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name); } /// <summary> /// 根据客户名称获取客户列表 /// </summary> /// <param name="name">客户名称</param> /// <returns></returns> public List<CustomerInfo> FindByName(string name) { string condition = string.Format("Name like '%{0}%' ", name); return baseDal.Find(condition); } #region 使用存储过程 public bool StorePorc_Insert(CustomerInfo info, DbTransaction trans = null) { ICustomer dal = baseDal as ICustomer; return dal.StorePorc_Insert(info, trans); } public bool StorePorc_Update(CustomerInfo info, DbTransaction trans = null) { ICustomer dal = baseDal as ICustomer; return dal.StorePorc_Update(info, trans); } public List<CustomerInfo> StorePorc_GetAll(DbTransaction trans = null) { ICustomer dal = baseDal as ICustomer; return dal.StorePorc_GetAll(trans); } public DataTable StorePorc_GetAllToDataTable(DbTransaction trans = null) { ICustomer dal = baseDal as ICustomer; return dal.StorePorc_GetAllToDataTable(trans); } public CustomerInfo StorePorc_FindByID(string ID, DbTransaction trans = null) { ICustomer dal = baseDal as ICustomer; return dal.StorePorc_FindByID(ID, trans); } public bool StorePorc_ExistByID(string ID, DbTransaction trans = null) { ICustomer dal = baseDal as ICustomer; return dal.StorePorc_ExistByID(ID, trans); } public bool StorePorc_DeleteByID(string ID, DbTransaction trans = null) { ICustomer dal = baseDal as ICustomer; return dal.StorePorc_DeleteByID(ID, trans); } public int StorePorc_GetMaxAge() { ICustomer dal = baseDal as ICustomer; return dal.StorePorc_GetMaxAge(); } #endregion } 为了验证我们的实现是否能够正常处理,并顺利获取对应的对象或者集合,我们需要编写一些代码,用来对它进行测试。 测试的代码如下所示。 /// <summary> /// 测试存储过程的插入、修改、返回实体类、返回实体类集合、返回DataTable对象、输出参数等接口 /// </summary> private void btnTestStoreProc_Click(object sender, EventArgs e) { //定义一个实体类的数据 CustomerInfo info = new CustomerInfo(); info.Name = "测试名称"; info.Age = 20; //调用存储过程插入数据,并判断是否成功 bool inserted = BLLFactory<Customer>.Instance.StorePorc_Insert(info); Debug.Assert(inserted); //调用存储过程,获取输出参数,获得最大年龄值 int maxAge = BLLFactory<Customer>.Instance.StorePorc_GetMaxAge(); Debug.Assert(maxAge > 0); //调用存储过程,修改客户名称 info.Name = "修改名称"; bool updated = BLLFactory<Customer>.Instance.StorePorc_Update(info); //调用存储过程,获取最新的实体类对象,并对比是否修改成功 CustomerInfo newInfo = BLLFactory<Customer>.Instance.StorePorc_FindByID(info.ID); Debug.Assert(newInfo != null); Debug.Assert(newInfo.Name == info.Name); //调用存储过程,获取输出参数,判断指定ID记录是否存在 bool exist = BLLFactory<Customer>.Instance.StorePorc_ExistByID(info.ID); Debug.Assert(exist); //调用存储过程,获取全部实体列表集合,判断实体类列表是否正确 List<CustomerInfo> list = BLLFactory<Customer>.Instance.StorePorc_GetAll(); Debug.Assert(list.Count > 0); //调用存储过程,获取DataTable对象,判断集合不为空 DataTable dt = BLLFactory<Customer>.Instance.StorePorc_GetAllToDataTable(); Debug.Assert(dt.Rows.Count > 0); //调用存储过程,执行删除操作,并判断是否成功了 bool deleted = BLLFactory<Customer>.Instance.StorePorc_DeleteByID(info.ID); Debug.Assert(deleted); string result = "全部操作完成"; Console.WriteLine(result); MessageUtil.ShowTips(result); } 5、具体测试和验证 为了对他们进行测试,我们需要分别对SqlServer和Oracle进行测试,然后才能确认我们的实现是正确的。 分别在SQLServer和Oracle上运行存储过程脚本,创建对应的数据库脚本,如下所示。 测试Winform小程序,会得到成功的标志,标识所有的断言全部通过。   6、框架基类的演化提炼 本来写到上面小节,应该就可以告一段落了,因为功能也已经完成了,而且还是支持了两种不同的数据库,说明我们的实现和原先的想法都是正确的。 但是,我从来不喜欢臃肿的代码,我们留心回头看看前面的代码,两种不同数据库的实现很多是相似的,即使对于同一个数据库(如SQLServer)的存储过程接口实现,他们还是有很多优化的地方,代码依旧不够精简和优化,本小节就是专门针对这些进行提炼和优化的。 前面的框架介绍文章,我们可以了解到,数据访问接口实现层和接口定义层一样,都有一个基类,如基于SqlServer实现的基类为BaseDALSQL,这个基于SqlServer的数据访问基类,它也是继承自一个超级基类(大多数的实现在这里)AbstractBaseDAL。他们之间的继承关系如下所示,最终我们把提炼好的内容,放到这个AbstractBaseDAL就可以了,这样各个子类都可以进行调用,实现存储过程的处理。 对于存储过程的实现,我们分析一下各个接口,可以看到,输入参数是可选的,因为有些接口不需要输出参数;输出参数也是可选的,有些接口也不需要输出参数,返回的记录类型主要有bool类型,实体类型,实体集合类型,DataTable类型这几种,当然虽然有年龄接口的整形,但是这个是通过输出参数来获得的。 我们于是可以定义一个类似这样的通用接口参数集合,用来处理需要返回是否成功获取带有输出参数的,事务对象的接口,如下所示。 /// <summary> /// 执行存储过程,如果影响记录数,返回True,否则为False,修改并输出外部参数outParameters(如果有)。 /// </summary> /// <param name="storeProcName">存储过程名称</param> /// <param name="inParameters">输入参数,可为空</param> /// <param name="outParameters">输出参数,可为空</param> /// <param name="trans">事务对象,可为空</param> /// <returns>如果影响记录数,返回True,否则为False</returns> public bool StorePorcExecute(string storeProcName, Hashtable inParameters = null, Hashtable outParameters = null, DbTransaction trans = null) 它的实现基本上就是分为了几部分,第一部分是传入参数值(包括输入参数、输出参数的值),第二部是执行存储过程,三部分是获得输出参数并修改值即可。 具体的实现代码如下所示。 /// <summary> /// 执行存储过程,如果影响记录数,返回True,否则为False,修改并输出外部参数outParameters(如果有)。 /// </summary> /// <param name="storeProcName">存储过程名称</param> /// <param name="inParameters">输入参数,可为空</param> /// <param name="outParameters">输出参数,可为空</param> /// <param name="trans">事务对象,可为空</param> /// <returns>如果影响记录数,返回True,否则为False</returns> public bool StorePorcExecute(string storeProcName, Hashtable inParameters = null, Hashtable outParameters = null, DbTransaction trans = null) { Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(storeProcName); //参数传入 SetStoreParameters(db, command, inParameters, outParameters); //获取执行结果 bool result = false; if (trans != null) { result = db.ExecuteNonQuery(command, trans) > 0; } else { result = db.ExecuteNonQuery(command) > 0; } //获取输出参数的值 EditOutParameters(db, command, outParameters); return result; } 上面两部分红色哪里,因为他们在很多其他函数里面也通用,所以我就抽离作为一个私有函数了,就是传入参数,和传出结果的两部分。 由于输入输出参数都是可选的,因为我们不确定它是否存在值,所以我们分别对它进行了一定的处理,具体两个函数的代码如下所示。 /// <summary> /// 传入输入参数和输出参数到Database和DbCommand对象。 /// </summary> /// <param name="db">Database对象</param> /// <param name="command">DbCommand对象</param> /// <param name="inParameters">输入参数的哈希表</param> /// <param name="outParameters">输出参数的哈希表</param> private void SetStoreParameters(Database db, DbCommand command, Hashtable inParameters = null, Hashtable outParameters = null) { #region 参数传入 //传入输入参数 if (inParameters != null) { foreach (string param in inParameters.Keys) { object value = inParameters[param]; db.AddInParameter(command, param, TypeToDbType(value.GetType()), value); } } //传入输出参数 if (outParameters != null) { foreach (string param in outParameters.Keys) { object value = outParameters[param]; db.AddOutParameter(command, param, TypeToDbType(value.GetType()), 0);//size统一设置为0 } } #endregion } /// <summary> /// 执行存储过程后,获取需要输出的参数值,修改存储在哈希表里 /// </summary> /// <param name="db">Database对象</param> /// <param name="command">DbCommand对象</param> /// <param name="outParameters">输出参数的哈希表</param> private void EditOutParameters(Database db, DbCommand command, Hashtable outParameters = null) { #region 获取输出参数的值 if (outParameters != null) { ArrayList keys = new ArrayList(outParameters.Keys);//使用临时集合对象,避免迭代错误 foreach (string param in keys) { object retValue = db.GetParameterValue(command, param); object value = outParameters[param]; outParameters[param] = Convert.ChangeType(retValue, value.GetType()); } } #endregion } 这样我们就完成了一个普通存储过程该接口的通用处理了,但是我们知道,还有返回列表对象,列表集合,DataTable对象的几种不同方式,我们也应该要对他们进行一定的封装处理,已达到在子类能够很好使用的目的。 下面我把整个对这几部分封装的代码进行公布,它们的封装的代码如下所示(记得是放在超级抽象类上AbstractBaseDAL即可。 #region 存储过程执行通用方法 /// <summary> /// 执行存储过程,如果影响记录数,返回True,否则为False,修改并输出外部参数outParameters(如果有)。 /// </summary> /// <param name="storeProcName">存储过程名称</param> /// <param name="inParameters">输入参数,可为空</param> /// <param name="outParameters">输出参数,可为空</param> /// <param name="trans">事务对象,可为空</param> /// <returns>如果影响记录数,返回True,否则为False</returns> public bool StorePorcExecute(string storeProcName, Hashtable inParameters = null, Hashtable outParameters = null, DbTransaction trans = null) { Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(storeProcName); //参数传入 SetStoreParameters(db, command, inParameters, outParameters); //获取执行结果 bool result = false; if (trans != null) { result = db.ExecuteNonQuery(command, trans) > 0; } else { result = db.ExecuteNonQuery(command) > 0; } //获取输出参数的值 EditOutParameters(db, command, outParameters); return result; } /// <summary> /// 执行存储过程,返回实体列表集合,修改并输出外部参数outParameters(如果有)。 /// </summary> /// <param name="storeProcName">存储过程名称</param> /// <param name="inParameters">输入参数,可为空</param> /// <param name="outParameters">输出参数,可为空</param> /// <param name="trans">事务对象,可为空</param> /// <returns>返回实体列表集合</returns> public List<T> StorePorcToList(string storeProcName, Hashtable inParameters = null, Hashtable outParameters = null, DbTransaction trans = null) { Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(storeProcName); //参数传入 SetStoreParameters(db, command, inParameters, outParameters); #region 获取执行结果 List<T> result = new List<T>(); T entity = null; if (trans != null) { using (IDataReader dr = db.ExecuteReader(command, trans)) { while (dr.Read()) { entity = DataReaderToEntity(dr); result.Add(entity); } } } else { using (IDataReader dr = db.ExecuteReader(command)) { while (dr.Read()) { entity = DataReaderToEntity(dr); result.Add(entity); } } } #endregion //获取输出参数的值 EditOutParameters(db, command, outParameters); return result; } /// <summary> /// 执行存储过程,返回DataTable集合,修改并输出外部参数outParameters(如果有)。 /// </summary> /// <param name="storeProcName">存储过程名称</param> /// <param name="inParameters">输入参数,可为空</param> /// <param name="outParameters">输出参数,可为空</param> /// <param name="trans">事务对象,可为空</param> /// <returns>返回DataTable集合</returns> public DataTable StorePorcToDataTable(string storeProcName, Hashtable inParameters = null, Hashtable outParameters = null, DbTransaction trans = null) { Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(storeProcName); //参数传入 SetStoreParameters(db, command, inParameters, outParameters); #region 获取执行结果 DataTable result = null; if (trans != null) { result = db.ExecuteDataSet(command, trans).Tables[0]; } else { result = db.ExecuteDataSet(command).Tables[0]; } if (result != null) { result.TableName = "tableName";//增加一个表名称,防止WCF方式因为TableName为空出错 } #endregion //获取输出参数的值 EditOutParameters(db, command, outParameters); return result; } /// <summary> /// 执行存储过程,返回实体对象,修改并输出外部参数outParameters(如果有)。 /// </summary> /// <param name="storeProcName">存储过程名称</param> /// <param name="inParameters">输入参数,可为空</param> /// <param name="outParameters">输出参数,可为空</param> /// <param name="trans">事务对象,可为空</param> /// <returns>返回实体对象</returns> public T StorePorcToEntity(string storeProcName, Hashtable inParameters = null, Hashtable outParameters = null, DbTransaction trans = null) { Database db = CreateDatabase(); DbCommand command = db.GetStoredProcCommand(storeProcName); //参数传入 SetStoreParameters(db, command, inParameters, outParameters); #region 获取执行结果 T result = null; if (trans != null) { using (IDataReader dr = db.ExecuteReader(command, trans)) { if (dr.Read()) { result = DataReaderToEntity(dr); } } } else { using (IDataReader dr = db.ExecuteReader(command)) { if (dr.Read()) { result = DataReaderToEntity(dr); } } } #endregion //获取输出参数的值 EditOutParameters(db, command, outParameters); return result; } /// <summary> /// 传入输入参数和输出参数到Database和DbCommand对象。 /// </summary> /// <param name="db">Database对象</param> /// <param name="command">DbCommand对象</param> /// <param name="inParameters">输入参数的哈希表</param> /// <param name="outParameters">输出参数的哈希表</param> private void SetStoreParameters(Database db, DbCommand command, Hashtable inParameters = null, Hashtable outParameters = null) { #region 参数传入 //传入输入参数 if (inParameters != null) { foreach (string param in inParameters.Keys) { object value = inParameters[param]; db.AddInParameter(command, param, TypeToDbType(value.GetType()), value); } } //传入输出参数 if (outParameters != null) { foreach (string param in outParameters.Keys) { object value = outParameters[param]; db.AddOutParameter(command, param, TypeToDbType(value.GetType()), 0);//size统一设置为0 } } #endregion } /// <summary> /// 执行存储过程后,获取需要输出的参数值,修改存储在哈希表里 /// </summary> /// <param name="db">Database对象</param> /// <param name="command">DbCommand对象</param> /// <param name="outParameters">输出参数的哈希表</param> private void EditOutParameters(Database db, DbCommand command, Hashtable outParameters = null) { #region 获取输出参数的值 if (outParameters != null) { ArrayList keys = new ArrayList(outParameters.Keys);//使用临时集合对象,避免迭代错误 foreach (string param in keys) { object retValue = db.GetParameterValue(command, param); object value = outParameters[param]; outParameters[param] = Convert.ChangeType(retValue, value.GetType()); } } #endregion } #endregion 封装好这些超级基类后,我们在数据访问层里面,就可以很好地简化对存储过程的调用了,而且他们的做法都很类似,我们可以对比一下,它们调用存储过程的实现真正简化了很多。 例如对于SqlServer数据访问层,使用超级基类的接口,我们简化代码如下所示。 public bool StorePorc_Insert(CustomerInfo info, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("ID", info.ID); inParameters.Add("Name", info.Name); inParameters.Add("Age", info.Age); return StorePorcExecute("T_Customer_Insert", inParameters, null, trans); } public bool StorePorc_Update(CustomerInfo info, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("ID", info.ID); inParameters.Add("Name", info.Name); inParameters.Add("Age", info.Age); return StorePorcExecute("T_Customer_UpdateByID", inParameters, null, trans); } public List<CustomerInfo> StorePorc_GetAll(DbTransaction trans = null) { return StorePorcToList("T_Customer_SelectAll", null, null, trans); } public DataTable StorePorc_GetAllToDataTable(DbTransaction trans = null) { return StorePorcToDataTable("T_Customer_SelectAll", null, null, trans); } public CustomerInfo StorePorc_FindByID(string ID, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("ID", ID); return StorePorcToEntity("T_Customer_SelectByID", inParameters, null, trans); } public bool StorePorc_ExistByID(string ID, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("ID", ID); Hashtable outParameters = new Hashtable(); outParameters.Add("Exist", 0); StorePorcExecute("T_Customer_ExistByID", inParameters, outParameters, trans); int exist = (int)outParameters["Exist"]; return exist > 0; } public bool StorePorc_DeleteByID(string ID, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("ID", ID); return StorePorcExecute("T_Customer_DeleteByID", inParameters, null, trans); } public int StorePorc_GetMaxAge() { Hashtable outParameters = new Hashtable(); outParameters.Add("MaxAge", 0); StorePorcExecute("T_Customer_MaxAge", null, outParameters, null); int MaxAge = (int)outParameters["MaxAge"]; return MaxAge; } 对于Oracle数据访问层的实现来说,它的接口实现一样简单,只是参数命名有所不同而已。 public bool StorePorc_Insert(CustomerInfo info, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("p_ID", info.ID); inParameters.Add("p_Name", info.Name); inParameters.Add("p_Age", info.Age); return StorePorcExecute("T_Customer_Insert", inParameters, null, trans); } public bool StorePorc_Update(CustomerInfo info, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("p_ID", info.ID); inParameters.Add("p_Name", info.Name); inParameters.Add("p_Age", info.Age); return StorePorcExecute("T_Customer_UpdateByID", inParameters, null, trans); } public List<CustomerInfo> StorePorc_GetAll(DbTransaction trans = null) { return StorePorcToList("T_Customer_SelectAll", null, null, trans); } public DataTable StorePorc_GetAllToDataTable(DbTransaction trans = null) { return StorePorcToDataTable("T_Customer_SelectAll", null, null, trans); } public CustomerInfo StorePorc_FindByID(string ID, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("p_ID", ID); return StorePorcToEntity("T_Customer_SelectByID", inParameters, null, trans); } public bool StorePorc_ExistByID(string ID, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("p_ID", ID); Hashtable outParameters = new Hashtable(); outParameters.Add("p_Exist", 0); StorePorcExecute("T_Customer_ExistByID", inParameters, outParameters, trans); int exist = (int)outParameters["p_Exist"]; return exist > 0; } public bool StorePorc_DeleteByID(string ID, DbTransaction trans = null) { Hashtable inParameters = new Hashtable(); inParameters.Add("p_ID", ID); return StorePorcExecute("T_Customer_DeleteByID", inParameters, null, trans); } public int StorePorc_GetMaxAge() { Hashtable outParameters = new Hashtable(); outParameters.Add("p_MaxAge", 0); StorePorcExecute("T_Customer_MaxAge", null, outParameters, null); int MaxAge = (int)outParameters["p_MaxAge"]; return MaxAge; } 以上就是我针对《Winform开发框架之存储过程的支持--存储过程的实现和演化提炼》这个主题进行的介绍和分析,希望对大家有所帮助,也希望结合我的框架,迅速开发各种不同的项目。 文章内容有点长,感谢您的耐心阅读和支持。 Winform开发框架之存储过程的支持--存储过程的实现和演化提炼(1) Winform开发框架之存储过程的支持--存储过程的实现和演化提炼(2) 本文转自博客园伍华聪的博客,原文链接:Winform开发框架之存储过程的支持--存储过程的实现和演化提炼(2),如需转载请自行联系原博主。
文章
存储  ·  Oracle  ·  关系型数据库  ·  数据库
2017-12-04
MySQL 分页优化中的 “ INNER JOIN方式优化分页算法 ” 到底在什么情况下会生效?
最近无意间看到一个 MySQL 分页优化的测试案例,并没有非常具体地说明测试场景的情况下,给出了一种经典的方案。因为现实中很多情况都不是固定不变的,能总结出来通用性的做法或者说是规律,是要考虑非常多的场景的;同时,面对能够达到优化的方式要追究其原因,同样的做法,换了个场景,达不到优化效果的,还要追究其原因。 个人对此场景在不用情况表示怀疑,然后自己测试了一把,果然发现一些问题,同时也证实了一些预期的想法。 本文就 MySQL 分页优化,从最最简单的情况出发,来做一个简单的分析。 另:本文测试环境是最最低配置的云服务器,相对来说服务器硬件环境有限,不过对于不同的语句(写法)应该是“平等的”。 20170916补充: 想想用脚趾头就能明白: 如果分页排序字段是聚集索引,完全没必要对索引分页再查询数据,因为索引就是数据本身;如果是非聚集索引,先对索引分页,然后再利用索引去查询数据,先分页索引确实可以减少扫描的范围;如果经常按照2中的方式查询,也就是按照非聚集索引排序查询,那么为什么不在该列上建立聚集索引呢。MySQL 经典的分页“优化”做法 MySQL 分页优化中,有一种经典的问题,在查询越“靠后”的数据越慢(取决于表上的索引类型,对于B树结构的索引,SQL Server 中也一样)。 select * from t order by id limit m,n。 也即随着M的增大,查询同样多的数据,会越来越慢。面对这一问题,于是就产生了一种经典的做法,类似于(或者变种)如下的写法:先把分页范围内的id单独找出来,然后再跟基表做关联,最后查询出来所需要的数据。 select * from t inner join (select id from t order by id limit m,n)t1 on t1.id = t.id 这种做法是不是总是生效的,或者说是在什么情况下后者才能到达到优化的目的?有没有做了改写之后无效甚至变慢的情况? 与此同时,绝大多数查询都是有筛选条件的,如果有筛选条件的情况,SQL 语句就变成了: select * from t where *** order by id limit m,n 如果如法炮制,改写成类似: select * from t inner join (select id from t where *** order by id limit m,n )t1 on t1.id = t.id 在这种情况下,改写后的 SQL 语句还能达到优化的目的吗? 测试环境搭建 测试数据比较简单,通过存储过程循环写入测试数据,测试表的 InnoDB 引擎表。 这里要注意的是日志写入模式一定要修改成 innodb_flush_log_at_trx_commit = 2,否则默认情况下,500w 数据,估计一天都写不完,这个与日志写入模式有关,就不多说了。 分页查询优化的缘由 首先还是先看一下这个经典的问题,分页的时候,越“靠后”查询相应越慢的情况。 测试一:查询第1-20行的数据,0.01秒 同样是查询20行数据,查询相对“靠后”的数据,比如这里的从 4900001-4900020 行数据的情况,用时1.97秒。 从中可以看到,查询条件不变的情况下,越往后查询,查询效率越低,可以简单理解成:同样搜索20行数据,越是靠后的数据,查询代价越大。至于为什么后一种效率较低,后面会慢慢分析。 测试环境是 centos 7 ,MySQL 5.7,测试表的数据是 500W。 重现经典分页“优化”,当没有筛选条件,排序列为聚集索引的时候,并不会有所改善。 这里来对比以下两种写法在聚集索引列作为排序条件时候的性能。 select * from t order by id limit m,n。 select * from t inner join (select id from t order by id limit m,n)t1 on t1.id = t.id 第一种写法: select * from test_table1 order by id asc limit 4900000,20; 测试结果见截图,执行时间为8.31秒。 第二种改写后的写法: select t1.* from test_table1 t1 inner join (select id from test_table1 order by id limit 4900000,20)t2 on t1.id = t2.id; 执行时间为8.43秒。 这里很清楚,通过经典的改写方法改写之后,性能能毫无提升,甚至还有一点点变慢了,实际测试上表现为两者在性能上并没有明显的线性差异,这两者楼主是做了多次测试的。 我个人看到类似结论非要测一下不可的,这个东西不能靠蒙,或者靠运气什么的,能提高效率是为什么,不能提高又是为什么。 那么为什么改写之后的写法没有像传说中的那种提升性能? 是什么导致当前这个改写没有到达提升性能的目的? 后者能够提升性能的原理是什么? 首先看一下测试表的表结构,排序列上是有索引,这一点是没有问题的,关键是这个排序列上的索引是主键(聚集索引)。 为什么排序列上是聚集索引的时候,相对“优化”改写之后的 SQL 并不能达到“优化”的目的? 在排序列为聚集索引列的情况下,两者都是顺序扫描表来实现查询符合条件的数据的。后者虽然是先驱动一个子查询,然后再用子查询的结果驱动主表,但是子查询并没有改变“顺序扫描表来实现查询符合条件的数据的”做法,当前情况下,甚至改写后的做法显得画蛇添足。 参考如下两者执行计划,第一个截图的执行计划的一行,与改写后的 SQL 的执行计划的第三行(id =2 的那一行),基本上一样。 当没有筛选条件,排序列为聚集索引时候的分页查询,所谓的分页查询优化只不过是画蛇添足。 目前来看,查询上述数据,两种方式都非常慢,那如果要查询上述的数据,该如何做?还是要看为什么慢,首先要理解B数的平衡性结构,在我自己粗略的理解来看,如下图,当查询的数据“靠后”的时候,实际上是偏离在B树索引的一个方向,如下两个截图所示的目标数据其实平衡树上的数据,没有所谓的“靠前”与“靠后”,“靠前”与“靠后”都是相对于对方来说的,或者说是从扫描的方向上来看的从一个方向上看“靠后的”数据,从一个方向看就是“靠前的”,前后不是绝对的。 如下两个截图是B树索引结构的粗略表现形式,假如目标数据的位置固定的情况下,所谓的“靠后”是相对与从左向右来说的; 如果从右向左看,之前所谓靠后的数据实际上是“靠前”的。 只要数据是靠前的,要高效低找到这部分数据,还是可以的。MySQL 中应该也有类似于 SQL Server 中的正向(forwarded)和反向扫描(backward)的做法。 如果对于靠后的数据,采用反向扫描,应该就可以很快找到这个部分数据,然后对找到的数据在再次排序(asc),结果应该是一样的。 首先来看效果:结果跟上面的查询一模一样,这里仅耗时0.07秒,之前的两种写法均超过了8秒,效率有上百倍的差距。 至于这个是为什么,我想根据上面的阐述,自己应该能够体会的到,这里附上这个SQL。 如果经常查询所谓的靠后的数据,比如说Id较大的数据,或者说是时间维度上较新的数据,可以采用倒叙扫描索引的方式来实现高效分页查询。 (这里请计算好数据所在的分页,同样的数据,正序和倒序其起始“页码”是不同的) select* from ( select * from test_table1 order by id desc limit 99980,20 ) t order by id; 当没有筛选条件,排序列为非聚集索引的时候,会有所改善。 这里对测试表 test_table1 做出如下改变: 增加一个 id_2 列;该字段上创建一个唯一索引;该字段用对应的主键 Id 填充;上面的测试是按照主键索引(聚集索引)来排序的,现在来按照非聚集索引排序,也即新增的这个列 id_2 来排序,测试一开始提到的两种分页方法。 首先来看第一种写法: select * from test_table1 order by id_2 asc limit 4900000,20; 执行时间为1分钟多一点,暂且认其为60秒。 第二种写法: select t1.* from test_table1 t1 inner join (select id from test_table1 order by id_2 limit 4900000,20)t2 on t1.id = t2.id; 执行时间1.67秒。 从这种情况来看,也就是说排序列为非聚集索引列的时候,后一种写法确实能大幅度地提升效率。差不多有40倍的提升。 那么原因在何呢? 首先来看第一种写法的执行计划,可以简单理解为这个 SQL 的执行时做全表扫描之后,然后重新按照 id_2 排序,最后取最前20条数据。全表扫描本身就是一个非常耗时的过程,排序也是一个非常大的代价,因此表现为性能非常的低下。 再来看后者的执行计划,他是首先子子查询中,按照 id_2 上的索引顺序扫描,然后用符合条件的主键 Id 去表中查询数据。这样的话,避免了查询出来大量的数据然后重新排序(Using filesort)。 如果了解 SQL Server 执行计划的情况下,后者与前者相比,应该还有避免了频繁的回表(SQL Server 中叫做 key lookup 或者书签查找的过程,可以认为是子查询驱动外层表查询符合条件的20条的数据的过程是一个批量的,一次性的。 其实,只有在当前情况下,也就是说排序列为非聚集索引列的时候,改写后的 SQL 才能提升分页查询的效率。 即便如此,此方式“优化”过的分页语句,还是与如下写法的分页效率有比较大的差别的上面也看到了,返回同样的数据,如下的查询是0.07秒,比这里的1.67秒还是高2个数量级的。 select* from ( select * from test_table1 order by id desc limit 99980,20 ) t order by id; 另外一个,想提到的问题就是,如果经常性分页查询,还要按照某种顺序,那么为什么不在这个列上建立一个聚集索引。比如语句自增 Id 的,或者时间+其他字段确保唯一性的,MySQL 会在主键上自动创建聚集索引。然后有了聚集索引,“靠前”与“靠后”仅仅是一个相对的逻辑上的概念了,如果多数时候是想得到“靠后”或者较新的数据,就可以采用上述写法。 当存在筛选条件的情况下,分页查询的优化 这一部分想了想,情况太复杂了,很难概括出来一种非常具有代表性的案例,因此就不过多地做测试了。 select * from t where *** order by id limit m,n 比如刷选条件本身就很高效,一过滤出来仅剩下很少一部分数据,那么改不改写 SQL 意义也不大,因为筛选条件本身就可以做到很高效的筛选;比如刷选条件本身作用不大(过滤后数据量依然巨大),这种情况其实又回到了不存在筛选条件的情况,还有取决于如何排序,正序还是倒序等等;比如筛选条件本身作用不大(过滤后数据量依然巨大),要考虑的一个很实际的问题是数据分布,数据的分布也会影响的 SQL 的执行效率(sqlserver 中的经历,MySQL 应该差别不大);本身查询比较复杂的情况下,很难说用某种方式就可以达到高效的目的。情况越复杂,越是难以总结出来一种通用性的规律或者说是方法,一切都要以具体情况来看待,很难下一个定论。这里对于查询加上筛选条件的情况,就不做一一分析了,不过可以肯定的是,脱离了实际场景,肯定没有一个固化的方案。 另外,对于查询当前页数据时候,利用上一页查询的最大值做筛选条件,也可以很快滴找到当前页的数据,这样当然没有问题,但这属于另外一个做法,不在本文讨论之列。 补充一个在 SQL Server 下的测试结果,如果是非聚集索引,如果查询排序的列是一个单列索引,分页方式并不能提升效率。 create table TestPaging ( id int identity(1,1), name varchar(50), other varchar(100) ) declare @i int = 0 while @i<100000 begin insert into TestPaging values (NEWID(),NEWID()) set @i = @i + 1 end create index idx on TestPaging(name) 从执行计划可以看出,查询 Id 的子查询是一个全表扫描。 除非是一个符合索引,在表中数据比较大的情况下,才能提高效率(子查询进行索引扫描的代价要小于全表扫描的代价),不过话说回来,如果经常按照某个列排序分页,为什么该列上不建立成聚集索引呢? 总结 分页查询,越靠后越慢的情况,实则对于B树索引来说,靠前与靠后是一个逻辑上相对的概念,性能上的差异,是基于B树索引结构以及扫描方式有关的。如果加上筛选条件,情况将变得更加复杂,这个问题在 SQL Server 中的原理也是一样的,本来也在 SQL Server 中做了测试的,这里就不重复了。 当前这种情况,排序列不一定,查询条件不一定,数据分布不一定,就很难用一种特定的方法来实现“优化”,弄不好还起到画蛇添足的副作用。因此在做分页优化的时候,一定要根据具体的场景来做分析,方法也不一定只有一种,脱离实际场景的结论,都是扯犊子。唯有弄清楚这个问题的来龙去脉,才能游刃有余。 因此个人对于数据“优化”的结论,一定是具体问题具体分析,是很忌讳总结出来一套规则(规则1,2,3,4,5)给人“套用”,鉴于本人也很菜,就更不敢总结出来一些教条了。 原文发布时间为:2018-04-15 本文作者:lujun 本文来自云栖社区合作伙伴“数据和云”,了解相关信息可以关注“数据和云”。
文章
SQL  ·  算法  ·  关系型数据库  ·  测试技术  ·  索引
2018-04-16
跳转至:
数据库
249963 人关注 | 45741 讨论 | 67381 内容
+ 订阅
  • 让线程按顺序执行8种方法
  • 10本大数据领域经典好书,助力你的学习
  • 7 个对 Java 意义重大的性能指标,你知道几个?
查看更多 >
开发与运维
5315 人关注 | 127589 讨论 | 212648 内容
+ 订阅
  • Kruise Rollout:灵活可插拔的渐进式发布框架
  • 关于安卓打包脚本aab
  • 为什么需要微服务
查看更多 >
大数据
185163 人关注 | 24569 讨论 | 59767 内容
+ 订阅
  • 【自然语言处理(NLP)】基于GRU实现情感分类
  • 人工智能时代的新“文盲”:学不懂Python,就看不到未来
  • 10本大数据领域经典好书,助力你的学习
查看更多 >
云计算
21639 人关注 | 58091 讨论 | 42017 内容
+ 订阅
  • ESC使用体验
  • 高校学生暑假实践
  • Linux网络-IP协议详解
查看更多 >
人工智能
2649 人关注 | 10122 讨论 | 71489 内容
+ 订阅
  • 【自然语言处理(NLP)】基于GRU实现情感分类
  • 30年工作经验的程序员老师机,教你如何提高python效率
  • 人工智能时代的新“文盲”:学不懂Python,就看不到未来
查看更多 >