深入了解新的公共元数据
在我的前一篇文章我指出 Visual Studio 服务器资源管理器现在使用一个包含了 NET 数据提供程序(而不是 OLE DB 提供程序)列表的对话框来提示连接信息当您确定一个连接字符串并添加数据连接时每个数据连接也显示一个关于通过连接直接可见的数据库对象(如表视图和存储过程)的信息的树形结构但这些信息来自哪里呢?难道是 Visual Studio 仅为某些数据提供程序硬编码来生成这个信息而假如我编写我自己的数据提供程序或者从第三方购买一个的时候就留给我一个空节点?不在 Visual Studio 中并不是这样由于 ADONET 中的新架构 API所有这些有用的信息都将提供给您我不知道这是否是 Visual Studio 做到它的方法但是这里就是使用新的 API 来获得一个数据库中的表的列表的代码
// uses a ADONET named connection string in config file
// uses ADONET ProviderFactory and base classes
// see previous article
public static void GetListOfTables(string connectstring_name)
{
ConnectionStringSettings s =
ConfigurationSettingsConnectionStrings[connectstring_name];
DbProviderFactory f = DbProviderFactoriesGetFactory(sProviderName);
using (DbConnection conn = fCreateConnection())
{
connConnectionString = sConnectionString;
connOpen();
DataTable t = connGetSchema(Tables);
tWriteXml(tablesxml);
}
}
究竟谁需要元数据?
元数据是每个数据访问 API 的一部分尽管元数据的主要使用者是像 Visual Studio 这样的工具或者像 DeKlarit 这样的代码生成器但是它们并不是惟一的使用者应用程序包设计师可能允许最终用户通过向现有的表添加新表或新列来自定义一个应用程序当最终用户如此改变了数据库架构时一个通用查询和修改工具可以在维护备份和其他应用程序函数中使用元数据来包含用户的新表就像它们是应用程序附带的内置表一样程序员可以使用元数据来编写他们自己的派生自 SystemDataCommonDbCommandBuilder的自定义类并为使用 DataSet 创建插入更新和删除命令多数据库应用程序(即设计为在用户选择的数据库上运行的应用程序)的构建者可以尽可能多地使用元数据来维护公共代码库在需要时优化数据访问代码
通过一般元数据 API 来公开元数据要比让每个使用者使用特定于数据库的 API 要好这样工具编写人员可以维护一个可管理性更好的代码库这样的 API 还必须是非常灵活的因为在编写一般 API 来公开元数据时有四个障碍需要考虑
元数据集合和信息在数据库间是有差别的例如SQL Server 用户可能想要公开一个链接服务器的集合但是 Oracle 用户可能对关于 Oracle 序列的信息感兴趣
不仅在不同的数据库产品中而且即使在相同数据库的不同版本中存储公共数据库元数据的基础系统表都是不同的例如SQL Server 使用在一个sys架构下的新表(例如systables)公开它的元数据而 SQL Server 以前的版本使用元数据表(如 sysobjects£©来存储相同的数据
不同的程序可能有不同的元数据视图以一个例子来说许多程序员抱怨 Oracle 数据库中表的列表太长因为大多数元数据 API 将system表与用户表混在一起他们想要一个仅由他们定义的表组成的短列表
是否根本不支持元数据要提供多少元数据应该完全取决于提供程序的编写者
大部分数据库 API 提供一个标准的元数据集它是所有提供程序必须支持的并且允许提供程序编写者添加新的元数据表这与使用 ANSI SQL 标准采用的方法是一致的解决这一问题的标准的一部分是 Schema Schemata(INFORMATION_SCHEMA 和 DEFINITION_SCHEMA)的第 部分ANSI SQL INFORMATION_SCHEMA 定义了由一个兼容的数据库支持的标准的元数据视图集但即便是这个规范也需要有一个方法来解决上面这些问题它声明
实施者可以自由添加额外的表到 INFORMATION_SCHEMA 或添加额外的列到预定义的INFORMATION_SCHEMA 表
OLE DB 作为一个与 ANSI SQL 标准概念一致的数据访问 API 示例定义了一系列的名为架构行集合的元数据它从一个大致遵循 INFORMATION_SCHEMA 的预定义集开始并添加 OLE DB 特定的列到每个行中ADONET 提供了一个甚至更强大更灵活的机制来公开元数据
我能得到什么样的元数据?
ADONET 允许提供程序编写者公开 种不同类型的元数据这些主要的元数据 — 元数据集合或类别 — 在 SystemDataCommonDbMetaDataCollectionNames 类中被枚举出来
; MetaDataCollections — 可用元数据集合的列表
; Restrictions — 对于每个元数据集合存在一批可以用于限制被请求的架构信息范围的限定符
; DataSourceInformation — 关于数据提供程序引用的数据库实例的信息
; DataTypes — 一组关于数据库支持的每个数据类型的信息
; ReservedWords — 适用于该种数据库查询语言的保留字通常查询语言等同于一种 SQL 的方言
MetaDataCollections 是 INFORMATION_SCHEMA 集合的名称如表列或主键但是如果使用 DbConnectionGetSchema这些元数据类别也被认为是元数据这意味着在代码方面来说是这样这些集合可以像普通的元数据一样被获得
// gets information about database Views
Table t = connGetSchema(Views);
// gets information about collections exposed by this provider
// this includes the five metacollections described above
Table t = connGetSchema(DbMetaDataCollectionNamesMetaDataCollections);
// gets information about the Restrictions metacollection
Table t = connGetSchema(DbMetaDataCollectionNamesRestrictions);
// No argument overload is same as asking for MetaDataCollections
Table t = connGetSchema();
个元数据集合中的 个值得进一步解释
Restrictions
Restrictions 可以用来限制返回元数据的数量如果您熟悉 OLE DB 或 ADO那么术语restriction意味着在那些 API 中同样的内容作为示例让我们使用 MetaDataCollection列它是表中的列名称的集合这个集合可以用于获取所有表中的所有列但是此被请求的列集合会被数据库名称所有者/架构或者表限制每个元数据集合可以有不同数量的可能限制并且每个限制会有一个默认值在我们下面的示例中这里是一个对列元数据的限制的 XML 表示
清单 列集合上的 Restrictions(XML 格式)
<Restrictions>
<CollectionName>Columns</CollectionName>
<RestrictionName>Catalog</RestrictionName>
<RestrictionDefault>table_catalog</RestrictionDefault>
<RestrictionNumber></RestrictionNumber>
</Restrictions> <Restrictions>
<CollectionName>Columns</CollectionName>
<RestrictionName>Owner</RestrictionName>
<RestrictionDefault>table_schema</RestrictionDefault>
<RestrictionNumber></RestrictionNumber>
</Restrictions> <Restrictions>
<CollectionName>Columns</CollectionName>
<RestrictionName>Table</RestrictionName>
<RestrictionDefault>table_name</RestrictionDefault>
<RestrictionNumber></RestrictionNumber>
</Restrictions> <Restrictions>
<CollectionName>Columns</CollectionName>
<RestrictionName>Column</RestrictionName>
<RestrictionDefault>column_name</RestrictionDefault>
<RestrictionNumber></RestrictionNumber>
</Restrictions>
Restrictions 是使用一个重载的 DbConnectionGetSchema 指定的这些限制被指定为一个数组您可以将一个数组指定为和整个限制集合或者一个子集数组一样大因为RestrictionNumbers通常从最少限制向最多限制发展对您想要省略的限制值使用空值(不是数据库 NULL而是 NET NULL或者在 Visual Basic NET 中的 Nothing)例如
// restriction string array
string[] res = new string[];
// all columns all tables owned by dbo
res[] = dbo;
DataTable t = connGetSchema(Columns res);
// clear collection
for (int i = ; i < ; i++) res[i] = null;
// all columns all tables named authors any owner/schema
res[] = authors;
DataTable t = connGetSchema(Columns res);
// clear collection
for (int i = ; i < ; i++) res[i] = null;
// columns named au_lname
// all tables named authors any owner/schema
res[] = authors;