写这个文章源于早先对ADO.Net获取数据库元数据上的认识,去年我在阅读ADO.Net Core Reference的时候曾经注意过DataSet的FillSchema的这个方法。这方面,在我之前的随笔中提到过Typed DataSet,而FillSchem与WriteXmlSchema的结合使用可以获得数据库的表结构架构,从而使用相应工具生成强类型的DataSet。但是我记得作者建议在具体应用开发中尽量少用FillSchema这个方法,因为出于性能考虑,其一般只适合作为测试过程中的一个方法。
当时我的理解就是,这是一个获取数据库元数据的一个方便的方法,但是由于其对性能的影响,因此通常应用中比较少用。而在我后面的开发中也未曾有机会接触这个方法。
今年早先1月份的时候看DAAB,注意到其封装的DataCommand对象提供了动态获取存储过程信息的支持:DeriveParameters。当时我的第一印象是,这也是获取数据库的“元数据”,因为之前有过FillSchema对性能影响上的认识,我当时就产生了一个问号:这样做适合吗?自动填充Command对象的Parameter集合,会影响应用程序的性能吗?
就此我也请教过M$的专家,给我的回答是两者机制不同,后者对性能影响不大。
昨日翻倒年初对这个问题疑惑而提的一篇帖子,突然很想进一步找找这两中方法的区别之处,简单了解了一下,以下做个简单的归纳。
DeriveParameters方法
先说简单的一个。DeriveParameters是SqlCommandBuilder类的一个公共方法,提供一个SqlCommannd的参数,该Command对象作为获取到的Parameters的存放容器。其实SqlCommand本身就有一个DeriveParameters的方法,但是它是内部方法,而SqlCommandBuilder.DeriveParameters就是封装了该方法的调用:
1public static void DeriveParameters(SqlCommand command)
2{
3 SqlConnection.SqlClientPermission.Demand();
4 if (command == null)
5 {
6 // throw an exception
7 }
8 command.DeriveParameters();
9}
来看一下SqlCommand的DeriveParameters方法:
1internal void DeriveParameters()
2{
3
4 // Validate command type(is storedprocedure?) and command info
5
6
7 // Retrieve command text detail
8 string[] txtCommand = ADP.ParseProcedureName(this.CommandText);
9
10 SqlCommand cmdDeriveCommand = null;
11
12 this.cmdText = "sp_procedure_params_rowset";
13 if (txtCommand[1] != null)
14 {
15 this.cmdText = "[" + txtCommand[1] + "].." + this.cmdText;
16
17 if (txtCommand[0] != null)
18 {
19 this.cmdText = txtCommand[0] + "." + this.cmdText;
20 }
21
22 cmdDeriveCommand = new SqlCommand(this.cmdText, this.Connection);
23 }
24 else
25 {
26 cmdDeriveCommand = new SqlCommand(this.cmdText, this.Connection);
27 }
28 cmdDeriveCommand.CommandType = CommandType.StoredProcedure;
29 cmdDeriveCommand.Parameters.Add(new SqlParameter("@procedure_name", SqlDbType.NVarChar, 0xff));
30 cmdDeriveCommand.Parameters[0].Value = txtCommand[3];
31 ArrayList parms = new ArrayList();
32 try
33 {
34 try
35 {
36 using (SqlDataReader drParam = cmdDeriveCommand.ExecuteReader())
37 {
38 SqlParameter parameter = null;
39 while (drParam.Read())
40 {
41 parameter = new SqlParameter();
42 parameter.ParameterName = (string) drParam["PARAMETER_NAME"];
43 parameter.SqlDbType = MetaType.GetSqlDbTypeFromOleDbType((short) drParam["DATA_TYPE"], (string) drParam["TYPE_NAME"]);
44 object len = drParam["CHARACTER_MAXIMUM_LENGTH"];
45 if (len is int)
46 {
47 parameter.Size = (int) len;
48 }
49 parameter.Direction = this.ParameterDirectionFromOleDbDirection((short) drParam["PARAMETER_TYPE"]);
50 if (parameter.SqlDbType == SqlDbType.Decimal)
51 {
52 parameter.Scale = (byte) (((short) drParam["NUMERIC_SCALE"]) & 0xff);
53 parameter.Precision = (byte) (((short) drParam["NUMERIC_PRECISION"]) & 0xff);
54 }
55 parms.Add(parameter);
56 }
57 }
58 }
59 finally
60 {
61 cmdDeriveCommand.Connection = null;
62 }
63 }
64 catch
65 {
66 throw;
67 }
68
69 if (params.Count == 0)
70 {
71 // throw an exception that current storedprocedure does not exist
72 }
73
74 this.Parameters.Clear();
75 foreach (object parm in parms)
76 {
77 this._parameters.Add(parm);
78 }
79}
ADP.ParseProcedureName其实就是获取存储过程命令的细节信息,有兴趣的可以反编译来看看。
纵观整个方法,有效性验证-〉获取命令字符串-〉执行查询-〉填充参数列表-〉返回。应该是非常简洁明朗的,最多也就是在数据库Query的阶段需要有一个来回,其他操作根本就谈不上有什么复杂度,而且也不存在大数据的对象,对性能的损耗谈不上多巨大。
下面来看看FillSchema的处理过程
FillSchema方法
这个部分因为代码比较多,所以我就抽关键的部分来看一下。
首先,FillSchema是DataAdapter类定义的一个方法,而具体实现则是在该类的子类DBDataAdapter中完成的(SqlDataAdapter继承于DBDataAdapter)。
通过反编译,可以发现FillSchema的关键处理步骤是在其调用私有方法FillSchemaFromCommand来完成的。简单看一下该方法体的内容:
1private DataTable[] FillSchemaFromCommand(object data, SchemaType schemaType, IDbCommand command, string srcTable, CommandBehavior behavior)
2{
3 IDbConnection connection = DbDataAdapter.GetConnection(command, "FillSchema");
4 ConnectionState state = ConnectionState.Open;
5 DataTable[] arrTables = new DataTable[0];
6 try
7 {
8 try
9 {
10 DbDataAdapter.QuietOpen(connection, out state);
11 using (IDataReader reader = command.ExecuteReader((behavior | CommandBehavior.SchemaOnly) | CommandBehavior.KeyInfo))
12 {
13 if (reader == null)
14
分享到:
相关推荐
SQL注入是攻击者通过输入恶意SQL代码到输入字段,从而获取、修改或删除数据库信息的一种常见手段。ASP.NET可以通过使用参数化查询或存储过程来防止这种攻击。参数化查询使开发者能够将用户输入的数据作为参数传递,...
在本节"VS2010轻松学习C#-从零到深入-天轰穿.NET4趣味编程视频教程_第27讲:ADO.NET实例浅析"中,天轰穿老师将带领我们深入理解ADO.NET,并通过实例演示如何在实际项目中应用这一强大的数据访问技术。ADO.NET是.NET ...
[第27讲:ADO.NET实例浅析(C#视频教程 + C#源代码).zip] 根据【田洪川 天轰穿 C#视频教程】的【第27讲:ADO.NET实例浅析】实现,VS2010编译运行正常;SQL Server数据库文件包括2005和2008两个版本的。 源代码与...
ADO.NET是微软.NET框架中用于数据访问的核心组件,是ADO的升级版。它提供了连接模式(Connected)和非连接模式(Disconnected)两种工作方式。非连接模式是.NET推荐的方式,其中数据集(DataSet)对象扮演关键角色...
标题和描述中提到的是关于“SQL存储过程在.NET数据库中的应用”,主要探讨了...通过Visual Studio .NET IDE创建和调用存储过程,结合ADO.NET的SqlDataAdapter和DataSet,开发者可以构建高效、灵活的数据库解决方案。
浅析 ASP.NET 页面跳转 ASP.NET 页面跳转是一种常见的Web开发技术,涉及到页面间数据传递的方法。本文将讨论 ASP.NET 页面跳转的五种方法,分别是使用 Querystring 方法、隐藏域、ViewState、Cookie 和 Application...
本文将浅析ASP.NET中的万能JSON解析器。 首先,理解JSON的基本结构至关重要。JSON数据通常由键值对组成,其中键是字符串,值可以是各种数据类型,包括字符串、数字、布尔值、数组、对象等。在提供的示例中,展示了...
使用此解析器,开发者可以轻松地将JSON数据映射到.NET对象中,也可以将.NET对象序列化为JSON格式,从而实现客户端和服务端之间的数据交换。 5. 注意事项 - 代码示例是基于理论上的设计,实际使用中需要对可能出现的...
VB.NET语言经过长时间的发展,很多用户都很了解VB.NET语言了,这里我发表一个关于VB.Net语言 复制、删除文件的例子,和大家一起分享一下。
.NET是Microsoft公司提供解决未来计算需要的工具。在.NET Framework中提供了许多控件,可以解决编程中用户界面的设计和实现,但在实际应用中可能需要对系统提供的控件进行改进,如下拉列表不能折行显示。本文将介绍...
ASP.NET提供了丰富的特性来帮助开发者快速构建高性能的应用程序,其中包括安全性管理、数据库访问、页面生命周期管理等。 #### 生成随机密码 在用户注册过程中,生成一个随机的密码并通过电子邮件发送给用户进行...
SQL Server 2000 是微软公司推出的一款关系型数据库管理系统,它在2000年发布,作为SQL Server 7.0的后续版本,提供了更加稳定和可靠的数据存储和管理解决方案。由于文件内容存在一些扫描错误和文字丢失,文章核心...
ASP.NET程序设计课程教学改革是针对当前教育模式中存在的一些问题进行的改进措施。该课程在计算机科学教育中占有重要地位,因为它融合了多种技术,如计算机技术、软件技术、网络技术和数据库技术。然而,传统的教学...
### 浅析基于ASP.NET的网站安全漏洞及防范 #### 摘要 本文结合自行开发的远程教育训练系统过程中出现的安全测试问题,探讨了在ASP.NET开发环境下常见的几种安全漏洞,包括SQL注入式攻击、查询字符串式数据传递、绕...
浅析SQLServer2005数据库
ASP.NET 数据控件是开发Web应用程序时用于展示和操作数据的重要工具。在这篇文章中,我们将深入探讨五大ASP.NET数据控件:GridView、DetailsView、FormView、Repeater和DataList,了解它们的特点和应用场景。 首先...
接下来,我们需要创建一个ADO.NET的DataSet和DataTable对象,用于存储Excel中的数据: ```csharp DataSet dataSet = new DataSet(); DataTable dataTable = new DataTable(); ``` 然后,我们创建一个OLEDB连接,...