当前位置: 首页 > 编程日记 > 正文

浅析ado.net获取数据库元数据信息

写这个文章源于早先对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                        {
15                              return arrTables;
16                        }

17                        int tblIndex = 0;
18                        while (true)
19                        {
20                              if (0 < reader.FieldCount)
21                              {
22                                    try
23                                    {
24                                          string txtTableName = null;
25                                          SchemaMapping mapping = new SchemaMapping(this, reader, true);
26                                          if (data is DataTable)
27                                          {
28                                                mapping.DataTable = (DataTable) data;
29                                          }

30                                          else
31                                          {
32                                                mapping.DataSet = (DataSet) data;
33                                                txtTableName = DbDataAdapter.GetSourceTableName(srcTable, tblIndex);
34                                          }

35                                          mapping.SetupSchema(schemaType, txtTableName, falsenullnull);
36                                          DataTable currentTable = mapping.DataTable;
37                                          if (currentTable != null)
38                                          {
39                                                arrTables = DbDataAdapter.AddDataTableToArray(arrTables, currentTable);
40                                          }

41                                    }

42                                    finally
43                                    {
44                                          tblIndex++;
45                                    }

46                              }

47                              if (!reader.NextResult())
48                              {
49                                    return arrTables;
50                              }

51                        }

52                  }

53            }

54            finally
55            {
56                  DbDataAdapter.QuietClose(connection, state);
57            }

58      }

59      catch
60      {
61            throw;
62      }

63      return arrTables;
64}


首先,该操作含有一个数据库的Query操作,这里其实是调用DBDataAdapter的SelectCommand的对象,执行一次查询,然后遍历查询返回的所有表,每遍历到一个表的时候,通过该表的信息实例化一个SchemaMapping对象,再有该对象创建为DataSet/DataTable创建架构信息。

这里,DataSet/DataTable是作为参数提供的,整个处理过程,首先必然的需要完成一次查询操作,由于使用IDataReader,所以在查询之后的所有操作期间,连接是保持着的,这一定程度上占用了一些资源(也可以说这些资源还不算太昂贵);其次,实例化一个SchemaMapping对象(该对象是内部类,我在MSDN上没有查到相关介绍性资料),我简单看了一下这个类的代码,在我看来,它的处理过程应该是占据了整个过程蛮大一部分资源的,这方面属于个人见解。

由于我的认识上的有限,也为了保证文章的内容无误导,暂且说到这里。这个方法的进一步讨论希望留给有兴趣的朋友。

总结

以上是我对这两个方法认识方面简单的一个概括,其实从上面的描述,也打消了我原先认为的这两个方法在获取元数据上有本质的差别。个人认为,之所以获取结构性元数据的消耗大,是因为获取逻辑的繁琐以及使用的对象的庞大,而参数信息相对而言完全属于轻量级的东西,所以所谓性能上的差异并非因为获取机制的本质差异引起的。

相关文章:

账户密码策略修改

由于是虚拟测试环境所以AD 和 Exchange安装在同一台虚拟机上&#xff0c;所以修改账户密码策略已达到降低密码是设置的复杂度。 1.打开 --开始--管理工具--组策略管理 2.选择--Default Domain Policy 右键编辑 3.选择计算机设置--策略--安全设置--账户策略--密码策略 4.调整--密…

什么是新IP的四层网络技术

新IP技术共有四层&#xff1a;物理底层、网络服务、控制服务和编排。通过这四个层级实现网络虚拟化和软件定义网络&#xff0c;下面就来详细说一说什么是新IP的四层网络技术。 物理底层 新IP技术依然是一种基于硬件的技术&#xff0c;脱离不了物理底层&#xff0c;所有的虚拟软…

按拼音模糊匹配查询条件的生成类

转载了好几个地方&#xff0c;很难确定最早的出处。将源码贴出来先。1usingSystem; 2usingSystem.Text; 3usingSystem.IO; 45namespacets6{ 7 class test 8 { 9 private static string[] startChars {"啊", "芭", "擦","搭…

Java架构技术文档:并发编程+设计模式+常用框架+JVM+精选视频

本篇文章是我们整理的一份架构师的成长路线&#xff0c;包括了并发编程、设计模式、常用框架、中间件、微服务与分布式、常用工具、JVM、MySQL、数据结构与算法&#xff0c;还有架构师精选视频、架构师成长路线高清大图。又是新的一年&#xff0c;每一年都会有人在成为架构师的…

linux tune2fs简解(每日一令之五)

1:命令简介Linux下的文件检测命令&#xff0c;且可以自行定义自检周期2&#xff1a;用法[rootuyhd000225 ~]# tune2fs --help tune2fs 1.39 (29-May-2006) tune2fs&#xff1a;无效选项 -- - Usage: tune2fs [-c max_mounts_count] [-e errors_behavior] [-g group][-i interva…

物联网技术正颠覆传统医疗行业

如果你或你的爱人最近正在接受治疗&#xff0c;你可能会觉察到一些很酷的新设备可以辅助诊断和治疗。然而&#xff0c;你可能没有意识到&#xff0c;一部分这些设备已连接到互联网&#xff0c;成为物联网生态系统的一个重要组成部分。 到底如何连接核磁共振成像仪、CT扫描仪或实…

数组的进一步使用

数组是数据结构中最基本的结构形式&#xff0c;它是一种顺序式的结构&#xff0c;存储的是同一类型的数据。每个数组元素都拥有下标&#xff08;index&#xff09;和元素值&#xff08;value&#xff09;&#xff0c;下标方便存取数据&#xff0c;而元素值就是被存储的数据。 数…

百度香港二次上市,12 岁开发者、AI 机器人同台敲响“芯片代码锣”

整理 | AI科技大本营&#xff08;ID:rgznai100&#xff09;今日&#xff0c;继 2005 年百度在纳斯达克上市后&#xff0c;百度在香港的第二次上市。上市首日开盘价254港元每股&#xff0c;截至发稿&#xff0c;为 252 港元每股&#xff0c;总市值约为 7129 亿港元。现场“敲锣人…

Linux启动流程(二)

//...根据grub内核映像所在路径,读取内核映像&#xff0c;并进行解压缩操作。并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备&#xff0c;完成Linux核心环境的建立1.start_kernel(init/main.c)中调用一系列初始化函数:(1) 在屏幕上打印出当前的内核版本信息…

写代码可能是成为软件工程师最容易的部分

当然&#xff0c;写代码是超级重要的&#xff0c;但是我认为它只是整个过程中的一小部分&#xff0c;且不一定是最难学的。 学习如何写代码要花些时间&#xff0c;但是只要有足够的训练&#xff08;每天写代码&#xff0c;坚持数年&#xff09;&#xff0c;你就能真正擅长它。 …

不是“重复”造轮子,百度飞桨框架2.0如何俘获人心

2016 年&#xff0c;百度 PaddlePaddle 打响了国产深度学习框架开源的第一枪。 2019 年 4 月&#xff0c;在 Wave Summit 深度学习开发者峰会上&#xff0c;首次发布了PaddlePaddle 的中文名“飞桨”&#xff0c;开始强调自己更适合中国开发者&#xff0c;以及更加专注于深度学…

基于Sql Server 2008的分布式数据库的实践(一)

原文 基于Sql Server 2008的分布式数据库的实践&#xff08;一&#xff09; 配置Sql Server 2008&#xff08;Win7&#xff09; 1.打开SQL server2012&#xff0c;使用windows身份登录 2.登录后&#xff0c;右键选择“属性”。左侧选择“安全性”&#xff0c;选中右侧的“SQL S…

HttpHand和HttpModule的详细解释,包括Asp.Net对Http请求的处理流程。

了解当用户对一个.aspx页面提出请求时&#xff0c;后台的Web服务器的动作流程。当对这个流程了解后&#xff0c;我们就会明白HttpHandler和HttpModule的作用了。 首先&#xff0c;来了解一下IIS系统。它是一个程序&#xff0c;负责对网站的内容进行管理&#xff0c;以及对客户的…

WebGL初探

目前&#xff0c;我们有很多方案可以快速的接触到 WebGL 并绘制复杂的图形&#xff0c;但最后发现我们忽视了很多细节性的东西。当然&#xff0c;这对初学 WebGL 是有必要的&#xff0c;它能迅速提起我们对 WebGL 的学习兴趣。当学习到更加深入的阶段时&#xff0c;我们更想了解…

Linux下用C语言最基本的程序开发与调试

1.建一个目录2.写代码&#xff0c;建一个hello.c文件代码&#xff1a;view plaincopy to clipboardprint?#include "stdio.h" main() { printf("Hello Linux.\n") } #include "stdio.h" main() { printf("Hello Linux.\n")…

全面升级!星环科技基础软件再升级,赋能数字中国建设

3月24日&#xff0c;星环科技举行2021线上发布会&#xff0c;支持10种主流数据模型的多模数据平台和数据云产品、实现AI建模的全生命周期管理人工智能等产品新版本齐齐亮相。 星环科技坚持核心技术自主原创&#xff0c;专注于大数据基础平台、分布式关系型数据库、数据开发与智…

脚本中echo显示内容带颜色显示

脚本中echo显示内容带颜色显示,echo显示带颜色&#xff0c;需要使用参数-e格式如下&#xff1a;echo -e "\033[字背景颜色&#xff1b;文字颜色m字符串\033[0m"例如&#xff1a;echo -e "\033[41;36m something here \033[0m"其中41的位置代表底色&#xf…

Java 8默认方法会破坏你的(用户的)代码

Java 8的默认方法试图尝试更进一步简化Java API。不幸的是&#xff0c;这一最近的语言扩展带来了一系列复杂的规则&#xff0c;但只有少部分Java开发者意识到这一点。这篇文章告诉你为什么引入默认方法会破坏你的&#xff08;用户的&#xff09;代码。 起初看来&#xff0c;默认…

JPA多对多关联

关于JPA多对多关系&#xff0c;这是使用学生与教师来表示。一个Student由多个Teacher教&#xff0c;同样一个Teacher也可以教多个学生。Student类如下&#xff1a; 1 package com.yichun.bean;2 3 import java.util.HashSet;4 import java.util.Set;5 6 import javax.persisten…

上市之后,青云存储平台 QingStor 也要“进军”云原生

作者 | 夕颜头图 | 下载于东方IC出品 | CSDN云计算&#xff08;ID&#xff1a;CSDNcloud&#xff09;3 月 16 日&#xff0c;北京青云科技股份有限公司&#xff08;以下简称“青云科技”&#xff09;登录科创板&#xff0c;昔日里频频出现在公众视野的云计算企业&#xff0c;终…

SQL Server 存储过程的分页方案比拼

建立表&#xff1a; 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…

未来黑客入侵的不仅有电脑,还有人脑?

提到黑客入侵&#xff0c;我们能够知道的领域有很多&#xff0c;比如企业数据库、金融系统、个人信息、个人账户等。随着时代的变迁&#xff0c;人工智能、云计算、物联网等相继崛起&#xff0c;可能给黑客攻击的领域变得越发宽广。可是如果说黑客能攻击控制的不仅仅是电脑&…

不需xp_cmdshell支持在有注入漏洞的SQL服务器上运行CMD命令

我的BLOG里有一篇文章介绍了关于SQL注入的基本原理和一些方法。最让人感兴趣的也许就是前面介绍的利用扩展存储过程xp_cmdshell来运行操作系统的控制台命令。这种方法也非常的简单&#xff0c;只需使用下面的SQL语句&#xff1a;EXEC master.dbo.xp_cmdshell dir c:/但是越来越…

谷歌低调了 5 年的 Fuchsia OS,终于有望面世了!

种种迹象表明&#xff0c;低调了多年的 Fuchsia OS 可能就要出首个开发者版本了&#xff01;整理 | 郑丽媛出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;千呼万唤始出来&#xff0c;等待了五年&#xff0c;谷歌 Fuchsia OS 的首个开发者版本终于有望面世了&#…

chrom扩展开发-入门

2019独角兽企业重金招聘Python工程师标准>>> 先了解一下chrome的两种功能延伸方式&#xff1a; * 扩展&#xff08;Extension&#xff09; 1.指的是通过调用 Chrome 提供的 Chrome API 来扩展浏览器功能的一种组件&#xff0c;工作在浏览器层面&#xff0c;使用 HT…

你的机器学习模型为什么会出错?奉上四大原因解析及五条改进措施

对开发者来说&#xff0c;目前有一系列的机器学习模型可供选择。雷锋网(公众号&#xff1a;雷锋网)了解&#xff0c;可以用线性回归模型预测具体的数值&#xff0c;用逻辑回归模型对不同的运算结果进行归类&#xff0c;以及用神经网络模型处理非线性的问题等等。 不论哪一种&am…

释放CPU,算力经济下DPU芯片的发展机遇

当前承载算力的基础设施是各种规模的的数据中心&#xff0c;从几十个服务器节点的小规模企业级计算中心到数万个节点的巨型数据中心&#xff0c;通过云计算的模式对应用层客户提供存储、软件、计算平台等服务。这个生态直接承载了全球数十万亿美元规模的数字经济&#xff0c;而…

SQLserver安全设置攻略

日前SQL INJECTION的攻击测试愈演愈烈&#xff0c;很多大型的网站和论坛都相继被注入。这些网站一般使用的多为SQLSERVER数据库&#xff0c;正因为如此&#xff0c;很多人开始怀疑SQL SERVER的安全性。其实SQL SERVER2000已经通过了美国政府的C2级安全认证-这是该行业所能拥有的…

undefined symbol: ap_log_rerror;apache2.4与weblogic点so文件

没法子啊&#xff1b;只能用 httpd-2.2.26 https://www.google.com.hk/#newwindow1&qundefinedsymbol:ap_log_rerror&safestrictundefined symbol: ap_log_rerror[rootlocalhost local]# vi apache2/conf/httpd.conf[rootlocalhost local]# ./apache2/bin/apachectl s…

10个Java 8 Lambda表达式经典示例

Java 8 刚于几周前发布&#xff0c;日期是2014年3月18日&#xff0c;这次开创性的发布在Java社区引发了不少讨论&#xff0c;并让大家感到激动。特性之一便是随同发布的lambda表 达式&#xff0c;它将允许我们将行为传到函数里。在Java 8之前&#xff0c;如果想将行为传入函数&…