科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道[冷枫]剖析 .NET 托管提供程序

[冷枫]剖析 .NET 托管提供程序

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

剖析 .NET 托管提供程序

作者:冷枫 来源:CSDN 2007年9月24日

关键字: 冷枫 托管

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共2页)

与成熟的 OLE DB 提供程序相比,Microsoft .NET 托管提供程序有许多优点。首先,它实现了简化的数据访问结构,这种结构常常可提高性能,同时又不影响功能方面的能力。此外,.NET 托管提供程序通过方法和属性直接向使用者提供特定于提供程序的行为。它使用的接口集合也比 OLE DB 提供程序要少的多。最后但并非最不重要的是,.NET 托管提供程序工作在公共语言运行库 (CLR) 的边界内,无需 COM 交互。对于 SQL Server 7.0 和 SQL Server 2000 而言,托管提供程序直接挂接到线路级,获得了显著的性能优势。

*

.NET 数据提供程序提供的功能可分为以下两类:

通过 IDataAdapter 接口的方法的实现,支持 DataSet

支持连接的数据访问,包括表示连接、命令和参数的类

数据提供程序最简单的功能是,在读取和写入时只通过数据集与调用方交互。另一种情况是,您可以控制连接、事务处理以及执行直接命令,而不必考虑 SQL 语言。下图显示了 .NET 中两个标准托管提供程序(OLE DB 提供程序和用于 SQL Server 的提供程序)的类层次结构。


图 1. 托管提供程序连接、执行命令,并以特定于数据源的方式获取数据。

包装连接、命令和读取器的对象是特定于提供程序的,并且可能产生一组稍有不同的属性和方法。任何内部实现都严格地具备了数据库识别能力。在此架构范围之外的唯一的类是数据集。该类是所有提供程序所共有的,它作为断开连接的数据的一般容器。数据集类属于一种名为 System.Data 的超命名空间。特定于一个数据提供程序的类属于特定命名空间。例如,System.Data.SqlClientSystem.Data.OleDb 属于一个特定命名空间。上图显示的架构虽然并不过分简单,却是一种相当基本的架构。这是一种简化的架构,因为它不包括所涉及的所有类和接口。下图更接近真实情况。


图 2. 托管提供程序涉及的类

下表显示了构成 .NET 提供程序的接口的列表。

IDbConnection

表示一个与数据源建立的唯一会话

IDbTransaction

表示一个本地非分布式事务处理

IDbCommand

表示一个在连接到数据源时执行的命令

IDataParameter

允许将参数实现为命令

IDataReader

读取在执行命令后创建的只向前只读数据流

IDataAdapter

填充数据集并将数据集中的更改解析回数据源

IDbDataAdapter

提供对关系数据库执行典型操作(插入、更新、选择、删除)的方法

在所有接口中,只有 IDataAdapter 是强制性的,必须存在于每个托管提供程序中。如果您不打算实现其中的一个接口或给定接口的方法之一,无论如何都要公开该接口,但这样会引发 NotSupportedException 异常。只要有可能,应避免提供方法和接口的无操作实现,因为这种做法可能导致数据损坏,对于事务处理的提交/回滚尤其是这样。例如,提供程序无需支持嵌套事务处理,即使 IDbTransaction 接口的设计考虑到这种情况。

在进一步解释每个类在 .NET 提供程序的整体运行中所扮演的角色之前,我们先大概了解一下建议托管提供程序使用的命名约定。如果您打算自己编写提供程序,这方面的知识就非常有用。第一条准则是考虑命名空间。确保给自己的托管提供程序分配一个唯一的命名空间。接下来,使用在任何内部代码和客户端代码中标识提供程序的别名作为类的前缀。例如,使用 OdbcConnection、OdbcCommand、OdbcDataReader 等诸如此类的类名。在本文提到的情况中,别名为 Odbc。此外,尽量使用不同的文件来编译不同的功能。

实现连接

提供程序连接类从 IDbConnection 继承,并且必须公开 ConnectionString“状态”“数据库”ConnectionTimeout 属性。强制方法包括 “打开”“关闭”BeginTransactionChangeDatabaseCreateCommand。您不一定必须实现事务处理。下面的代码片断是一个用于实现连接的代码示例。

namespace DotNetMyDataProvider {  public class MyConnection : IDbConnection  {    private ConnectionState m_state;    private String m_sConnString;    public MyConnection () {m_state = ConnectionState.Closed;m_sConnString = "";    }    public MyConnection (String connString) {m_state = ConnectionState.Closed;m_sConnString = connString;    }    public IDbTransaction BeginTransaction() {      throw new NotSupportedException();    }    public IDbTransaction BeginTransaction(IsolationLevel level) {      throw new NotSupportedException();    } }}

您应该至少提供两个构造函数,其中一个是不带任何参数的默认构造函数。另一个建议的构造函数只接受连接字符串。通过 ConnectionString 属性返回连接字符串时,请确保返回的字符串始终是用户设置的那个字符串。唯一的异常可能是您也许希望删除的任何安全敏感信息导致的。

您在连接字符串中识别和支持的项取决于您本身,但无论何时,只要它有意义,就应该使用标准名称。“打开” 方法负责打开与数据源进行通信的物理信道。此操作不应该在调用 “打开” 方法之前进行。如果打开连接成为一个耗费内存的操作,可以考虑使用某种连接池。最后,如果期望提供程序在分布式事务处理中提供自动登记,登记应该在执行 “打开” 的期间进行。

使 ADO.NET 连接区别于其他连接(例如,ADO 连接)的一个要点是,您需要确保在可以执行任何命令之前创建和打开连接。客户端必须显式打开和关闭连接,没有任何方法会为客户端隐式打开和关闭连接。这种做法导致了某种程度的安全检查集中化。采用这种方法时,只有在获得连接后才执行检查,但提供程序中正巧涉及连接对象的所有其他类会同时受益。

方法 “关闭” 用于关闭连接。通常,“关闭” 应该只断开连接,并将对象返回池(如果有池)。您还可以实现 “处置” 方法来自定义对象的析构。连接的状态通过 ConnectionState 枚举数据类型来标识。当客户端使用连接时,您应该确保连接的内部状态与 “状态” 属性的内容相匹配。例如,当您提取数据时,将连接的 “状态” 属性设置为 ConnectionState.Fetching。

 

ODBC 连接

现在我们来看一个具体的 .NET 托管提供程序如何在实践中应用上述原则。为此,我们以一个最新托管提供程序为例,尽管它只出现在早期的测试版本中。这就是 ODBC 数据源的 .NET 提供程序。您可能已经注意到,OLE DB 的 .NET 提供程序在连接字符串中不支持 DSN 标记。这样的名称需要自动选择 MSDASQL 提供程序并搜索 ODBC 源。下面的代码显示了 ODBC.NET 如何声明其连接类:

public sealed class OdbcConnection : Component, ICloneable, IdbConnection

OdbcConnection 对象利用了 ODBC 的典型资源,例如,环境句柄和连接句柄。这些对象使用类私有成员在内部存储。该类同时用于 “关闭”“处置”。通常,您可以使用其中的任何一种方法来关闭连接,但必须在连接对象超出作用范围之前使用。否则,内存的释放(也就是 ODBC 句柄)将留给垃圾回收器,而您是无法控制其执行时间的。在连接池方面,OdbcConnection 类依靠 ODBC 驱动程序管理器的服务。

为了使用 ODBC.NET 提供程序(目前提供 Beta 1),您应该将 System.Data.Odbc 包括在内。这样可以确保提供程序使用用于 JET、SQL Server 和 Oracle 的驱动程序。

 

实现命令

命令对象为某些操作创建请求并将请求传递到数据源。如果返回结果,命令对象负责将结果作为定制的 DataReader 对象、标量值和/或通过输出参数进行打包和返回。根据数据提供程序的特性,您可以安排结果采用其他格式。例如,如果命令文本包括 FOR XML 子句,用于 SQL Server 的托管提供程序允许以 XML 格式获得结果。

类必须至少支持 CommandText 属性,并且至少支持文本命令类型。命令的分析和执行取决于提供程序。这是使提供程序有可能接受作为命令的任何文本或信息的一个关键要素。支持命令行为不是强制的,如果需要,您可以支持更多完全自定义的行为。

在命令中,连接可以与一个事务处理相关联。如果重置连接 — 并且用户应该能够在任何时候更改连接 — 那么首先禁用相应的事务处理对象。如果支持事务处理,则设置命令对象的 “事务” 属性时,应考虑额外的步骤,以确保您使用的事务处理已经与命令使用的连接相关联。

命令对象使用两个表示参数的类。一个类是 xxxParameterCollection,通过 Parameters 属性访问;另一个类是 xxxParameter,它表示集合中存储的单个命令参数。当然,xxx 代表特定于提供程序的别名。对于 ODBC.NET,这两个类就是 OdbcParameterCollection 和 OdbcParameter。

您可以对参数类使用 “新的” 运算符或通过命令对象的 CreateParameter 方法来创建特定于提供程序的命令参数。新创建的参数通过 Parameters 集合的方法填充和添加到命令的集合中。然后,用于命令执行的模块负责通过参数收集数据集。使用命名的参数(就像 SQL Server 提供程序那样)还是使用 ? 占位符(类似于 OLE DB 提供程序)则取决于您。

必须有一个有效的并且已打开的连接才能执行命令。使用任何标准类型的命令(例如,ExecuteNonQuery、ExecuteReader 和 ExecuteScalar)来执行命令。另外,还要考虑为 “取消”Prepare 方法提供实现。

 

ODBC 命令

OdbcCommand 类不支持通过 SQL 命令和存储过程传递命名的参数。您必须改用 ? 占位符。至少在这个早期版本中,它既不支持 “取消”,也不支持 Prepare。正如您预期的那样,ODBC .NET 提供程序要求 Parameters 集合中命令参数的数目与命令文本中找到的占位符的数目要匹配。否则,就会引发异常。下面的代码行显示了如何将一个新的参数添加到 ODBC 命令,同时为该参数赋值。

cmd.Parameters.Add("@CustID", OdbcType.Integer).Value = 99

注意,提供程序定义了自己的一组类型。枚举 OdbcType 包括 ODBC 的低级 API 确实可以识别的所有类型(并且只包括这些类型)。原来的 ODBC 类型非常相似,例如,SQL_BINARY、SQL_BIGINT 或 SQL_CHAR 和 .NET 类型。尤其是,ODBC 类型 SQL_CHAR 映射到 .NET String 类型。

 

实现数据读取器

数据读取器是提供程序为了使客户端以只向前方式读取数据而创建的一种已连接无缓存缓冲区。读取器的实际实现取决于提供程序的编写器。不过,应该注意遵循几条准则。

首先,DataReader 对象被返回用户时,应该始终处于打开状态并位于第一个记录之前。另外,用户不能直接创建 DataReader 对象。必须由命令对象创建和返回读取器。为此,您应该将构造函数标记为内部。采用 C# 时应使用关键字 internal

internal MyDataReader(object resultset){...}

采用 Visual Basic® .NET 时使用关键字 friend

Friend Sub New(ByRef resultset As object)      MyBase.New      ...End Sub

数据读取器必须至少有两个构造函数,一个接受查询的结果集,另一个接受用于执行命令的连接对象。只有当命令必须以 CommandBehavior.CloseConnection 的形式执行时才需要连接。在这种情况下,当 DataReader 对象关闭时,连接必须自动关闭。在内部,结果集可以采用满足您的需要的任何形式。例如,可以将结果集实现为数组或字典。

数据读取器应该正确管理属性 RecordsAffected。该属性只应用于包括插入、更新或删除命令的批处理语句。它通常不应用于查询命令。当读取器关闭时,您可能希望禁止某些操作和更改读取器的内部状态,以清理内部资源,如用于存储数据的数组。

数据读取器的 Read 方法始终前进到一个新的有效行(如果有任何新的有效行)。更重要的是,它应该只是使内部数据指针指向前,但不进行任何读取。实际的读取由其他特定于读取器的方法来完成,例如,GetStringGetValues。最后,NextResult 移到下一个结果集。基本上,它是将一个新的内部结构复制到 GetValues 等方法从其中进行读取的公用知识库。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章