[教程]SQL Server 2005:向系统表说再见

mikel阅读(673)

微软的SQL Server 数据库管理员 ,快快想一下!在不使用任何的文档的情况下,编写一个查询,从SQL Server 2000系统表中抽取索引的列表,然后列举每个索引中的字段,并判断这个字段是否按照升序或者降序进行排序。你有两分钟的时间。快!
  
   如果你现在真的停下阅读,开始用必不可少的两分钟时间思考这项不讨好的任务,那么现在你就陷入了一个大麻烦中,这里面涉及了系统索引、系统索引关键字, 系统字段,以及一些元数据函数,其中包括类似OBJECT_NAME 和INDEXKEY_PROPERTY这样的备用信息。到现在为止,要编写这样的一个查询很明显要花费远远超过2分钟的时间了。
  
  不幸的SQL Server 2000数据库管理员们,需要浏览深奥的系统表,这是这项使用数据库管理系统的工作中最糟糕的一部分。系统表,通常是有效率的,但是在我的印象里,它可从来不是为了用户友好设计的。
  
   幸运的是,眼前就有了救星。在SQL Server 2005中,系统表不见了。是的。不见了。再也不需要对陌生的位进行操作,也不需要找出神秘的编码方案——这在过去都是必需的。对于你们中间需要对遗留下 来的参考这些表的人来说,我知道你在想什么:无休止的机械的升级以保障与SQL Server 2005的兼容。但是还不要心生厌恶。系统中仍然存在类似系统表的对象,就是为了向下兼容的目的。但是表的自身是——或者是实际上应该是——被遗忘,像8 -tracks 和 Tab一样被投入了历史的垃圾桶中。
  
  那么这些表去了哪里呢?SQL Server 2005中的系统数据现在存储在隐藏的“资源”表中,这个表只能被服务器自身直接访问。低级用户(和数据库管理员)必须使用新的一系列的分类视图,这些视 图显示了从各种我们看不到也不能调用的隐藏表和各种隐藏函数中获得的数据。以前版本的SQL Server 中的系统表现在作为一系列所谓的(也相当正确的)“兼容视图”的形式实现。
  
  分类视图和它们的伙伴,动态管理视图(下面进行解 释),代表了一种处理元数据的方式,这些元数据是完全重新设计和重新思考出来的。没有了那些只会给数据库管理员一些底层数据的微小感觉的神秘的表,现在的 SQL Server提供了丰富的资源:SQL Server 2005中有超过200个分类和管理视图,取代了以前版本中大约50个的系统表。
  
   所有这些视图都可以在系统计划中找到。(计划是在SQL Server 2005中大大扩展了的安全特性。但是这是另一篇贴士的话题。)要看到可用视图的完全列表,SQL Server Management Studio扩展了所有数据库的系统视图树。或者通过T-SQL 从视图自身选择一个列表,并找出友好的易于理解的名字:
  
  Select name
  
  FROM sys.all_views
  
  Where is_ms_shipped = 1
  
  你还会发现再也不需要通过浏览文档来查找有关做某件关系系统数据的事情的线索。这些视图都有很明确的自我解释。
  
   有关视图名字的一些线索如下:那些前缀是dm_的是动态管理视图,通过类似当前会话、锁,以及系统资源的信息表示服务器的正在改变的状态。其他的视图都 可以认为是分类视图。那些前缀是all_的包含了有关系统对象(例如视图)和用户定义的对象的信息。那些没有all_前缀的只包含了用户定义的对象的信 息。在那些包括了系统对象的视图中,is_ms_shipping字段可用于区分用户定义对象和系统对象。如果is_ms_shipped字段的值为1, 则这一行代表了一个系统对象,否则,就是用户定义的对象。
  
  最后,让我们检查一些你可以从分类视图中获得数据类型。对于初学者,所 有常见的内容都可以获得。例如:查看索引中的数据,使用sys.indexes,而不是原先的sysindexes——奇怪的是,现在称之为 sys.sysindexes。对于约束,试试sys.check_constraints, sys.default_constraints, 或者 sys.key_constraints。看出这个趋势了吗?
  
  这篇贴士哪怕是没有简单的提到一句有关新的动态管理视图的 话,都是不完整的。这些视图是SQL Server存储新的元数据的强有力的工具,它们可以帮助数据库管理员快速解决问题并分析服务器的性能。其中的一些明星选手,包括 sys.dm_exec_query_stats,用来报告查询要求了多少个处理器时间;以及sys.dm_db_index_usage_stats, 用来帮助数据库管理员决定哪一个索引是最有用的,哪些是没有用的。
  
  对于这个巨大的元数据视图集合,还有更多的话需要说。但是现在,可以看看最近由微软发布在网上的beta版的SQL Server 2005在线书籍。系统视图主题提供了对这个强大的新的数据仓库的能力的整体描述。
  
  另外,以下是那个2分钟问题的解决方案。首先使用SQL Server 2000系统表。其次,可以尽早地阅读有关SQL Server 2005 分类视图的译本。
  

 

[文档]SQLServer系统表结构

mikel阅读(932)

sql server系统表详细说明

sysaltfiles  主数据库 保存数据库的文件

syscharsets  主数据库字符集与排序顺序

sysconfigures 主数据库 配置选项

 syscurconfigs 主数据库当前配置选项

  sysdatabases 主数据库服务器中的数据库

  syslanguages 主数据库语言

  syslogins 主数据库 登陆帐号信息

 sysoledbusers 主数据库 链接服务器登陆信息

  sysprocesses 主数据库进程

  sysremotelogins主数据库 远程登录帐号

  syscolumns 每个数据库 列

  sysconstrains 每个数据库 限制

  sysfilegroups 每个数据库 文件组

  sysfiles 每个数据库 文件

  sysforeignkeys 每个数据库 外部关键字

  sysindexs 每个数据库 索引

  sysmenbers 每个数据库角色成员

  sysobjects 每个数据库所有数据库对象

  syspermissions 每个数据库 权限

  systypes 每个数据库 用户定义数据类型

  sysusers 每个数据库 用户

sysaltfiles  页首

在特殊情况下,包含与数据库中的文件相对应的行。该表存储在 master 数据库中。

列名 数据类型 描述
fileid smallint 每个数据库的唯一文件标识号。
groupid smallint 文件组标识号。
size int 文件大小(以 8 KB 页为单位)。
maxsize int 最大文件大小(以 8 KB 页为单位)。0 值表示不增长,–1 值表示文件应一直增长到磁盘已满。
growth int 数据库的增长大小。0 值表示不增长。根据状态的值,可以是页数或文件大小的百分比。如果 status 为 0x100000,则 growth 是文件大小的百分比;否则是页数。
status int 仅限内部使用。
perf int 保留。
dbid smallint 该文件所属数据库的数据库标识号。
name nchar(128) 文件的逻辑名称。
filename nchar(260) 物理设备的名称,包括文件的完整路径。

>syscharsets 页首

每个字符集在表中各占一行,表中还包含定义供 Microsoft? SQL Server? 使用的排序次序。排序次序中的一个在 sysconfigures 中标记为默认排序次序,该次序是实际使用的唯一次序。

列名 数据类型 描述
type smallint 该行表示的实体类型。1001 是字符集;2001 是排序次序。
id tinyint 字符集或排序次序的唯一 ID。注意排序次序和字符集不能共享相同的 ID 号。保留从 1 到 240 的 ID 范围供 SQL Server 使用。
csid tinyint 如果该行表示字符集,则不使用该字段。如果该行表示排序次序,则该字段是在其上生成排序次序的字符集 ID。假设具有该 ID 的字符集行存在于该表中。
status smallint 内部系统状态信息位。
name sysname 字符集或排序次序的唯一名称。该字段必须只包含字母 A-Z 或 a-z、数字 0 – 9 和下划线 (_)。必须以字母开头。
description nvarchar(255) 字符集或排序次序功能的可选描述。
binarydefinition varbinary(255) 仅限内部使用。
definition image 字符集或排序次序的内部定义。该字段中的数据结构取决于类型。

sysconfigures 页首

用户设置的每个配置选项在表中各占一行。 sysconfigures 包含最近启动 Microsoft? SQL Server? 前定义的配置选项,还包含最近启动后设置的所有动态配置选项。该表只位于 master 数据库中。

列名 数据类型 描述
value int 变量的用户可修改值(仅在已执行 RECONFIGURE 后由 SQL Server 使用)。
config smallint 配置变量号。
comment nvarchar(255) 对配置选项的解释。
status smallint 表示选项状态的位图。可能的值包括:

0 = 静态(该设置在服务器重新启动时生效)。
1 = 动态(该变量在 RECONFIGURE 语句执行时生效)。
2 = 高级(仅当设置了显示高级选项时才显示该变量)。
3 = 动态和高级。

syscurconfigs 页首

每个当前配置选项各占一项。另外,该表还包含四个描述配置结构的项。 syscurconfigs 在由用户查询时动态生成。有关更多信息,请参见 sysconfigures

列名 数据类型 描述
value int 用户可修改的变量值(仅在已执行 RECONFIGURE 的情况下由 Microsoft? SQL Server? 使用)。
config smallint 配置变量号。
comment nvarchar(255) 对配置选项的解释。
status smallint 表示选项状态的位图。可能的值包括:

0 = 静态(该设置在服务器重新启动时生效)。
1 = 动态(该变量在 RECONFIGURE 语句执行时生效)。
2 = 高级(仅当设置了显示高级选项时才显示该变量)。
3 = 动态和高级。

 

sysdatabases 页首

Microsoft? SQL Server? 上的每个数据库在表中占一行。最初安装 SQL Server 时, sysdatabases 包含 master model msdb mssqlwebtempdb 数据库的项。该表只存储在 master 数据库中。

列名 数据类型 描述
name sysname 数据库的名称。
dbid smallint 数据库 ID。
sid varbinary(85) 数据库创建者的系统 ID。
mode smallint 用于创建数据库时在内部锁定该数据库。
status int 状态位,其中某些状态位可由用户使用 sp_dboption read only dbo use only single user 等)进行设置:

1 = autoclose ;使用 sp_dboption 设置。
4 = select into/bulkcopy ;使用 sp_dboption 设置。
8 = trunc. log on chkpt ;使用 sp_dboption 设置。
16 = torn page detection ,使用 sp_dboption 设置。
32 = loading
64 = pre recovery
128 = recovering
256 = not recovered
512 = offline ;使用 sp_dboption 设置。
1024 = read only ;使用 sp_dboption 设置。
2048 = dbo use only ;使用
sp_dboption 设置。
4096 = single user ;使用 sp_dboption 设置。
32768 = emergency mode
4194304 = autoshrink
1073741824 = cleanly shutdown

可以同时打开多个位。

status2 int 16384 = ANSI null default ;使用 sp_dboption 设置。
65536 = concat null yields null ,使用 sp_dboption 设置。
131072 = recursive triggers ,使用 sp_dboption 设置。
1048576 = default to local cursor ,使用 sp_dboption 设置。
8388608 = quoted identifier ,使用
sp_dboption 设置。
33554432 = cursor close on commit ,使用 sp_dboption 设置。
67108864 = ANSI nulls ,使用 sp_dboption 设置。
268435456 = ANSI warnings ,使用 sp_dboption 设置。
536870912 = full text enabled ,使用
sp_fulltext_database
设置。
crdate datetime 创建日期。
reserved datetime 留作以后使用。
category int 包含用于复制的信息位图:

1 = 已发布。
2 = 已订阅。
4 = 合并已发布。
8 = 合并已订阅。

cmptlevel tinyint 数据库的兼容级别。有关更多信息,请参见 sp_dbcmptlevel
filename nvarchar(260) 数据库主文件的操作系统路径和名称。
version smallint 创建数据库时使用的 SQL Server 代码内部版本号。仅供 SQL Server 工具在内部用于升级处理。

syslanguages 页首

出现在 Microsoft? SQL Server? 中的每种语言在表中各占一行。虽然美国英语不在 syslanguages 内,但该表始终可由 SQL Server 使用。该表只存储在 master 数据库中。

列名 数据类型 描述
langid smallint 唯一语言 ID。
dateformat nchar(3) 日期顺序(如 DMY)。
datefirst tinyint 一周的第一天:1 表示星期一,2 表示星期二,依此类推,直到 7 表示星期日。
upgrade int 留作系统使用。
name sysname 正式语言名称(例如,fran?ais)。
alias sysname 备用语言名称(如 French)。
months nvarchar(372) 按从一月到十二月的顺序排列的用逗号分隔的月份全称列表,每个名称最多包含 20 个字符。
shortmonths varchar(132) 按从一月到十二月的顺序排列的用逗号分隔的缩写月份名称列表,每个名称最多包含 9 个字符。
days nvarchar(217) 按从一月到十二月的顺序排列的用逗号分隔的天名称列表,每个名称最多包含 30 个字符。
lcid int 此种语言的 Microsoft Windows NT? 区域设置 ID。
mslangid smallint SQL Server 消息组 ID。

安装了 SQL Server 提供的三十三种语言。下面是语言列表。

用英语表示的名称 NT LCID SQL Server 消息组 ID
English 1033 1033
German 1031 1031
French 1036 1036
Japanese 1041 1041
Danish 1030 1030
Spanish 3082 3082
Italian 1040 1040
Dutch 1043 1043
Norwegian 2068 2068
Portuguese 2070 2070
Finnish 1035 1035
Swedish 1053 1053
Czech 1029 1029
Hungarian 1038 1038
Polish 1045 1045
Romanian 1048 1048
Croatian 1050 1050
Slovak 1051 1051
Slovene 1060 1060
Greek 1032 1032
Bulgarian 1026 1026
Russian 1049 1049
Turkish 1055 1055
British English 2057 1033
Estonian 1061 1061
Latvian 1062 1062
Lithuanian 1063 1063
Brazilian 1046 1046
Traditional Chinese 1028 1028
Korean 1042 1042
Simplified Chinese 2052 2052
Arabic 1025 1025
Thai 1054 1054

syslogins 页首

每个登录帐户在表中占一行。

列名 数据类型 描述
sid varbinary(85) 安全标识符。
status smallint 仅限内部使用。
createdate datetime 添加登录的日期。
updatedate datetime 更新登录的日期。
accdate datetime 仅限内部使用。
totcpu int 仅限内部使用。
totio int 仅限内部使用。
spacelimit int 仅限内部使用。
timelimit int 仅限内部使用。
resultlimit int 仅限内部使用。
name varchar(30) 用户的登录 ID。
dbname nvarchar(128) 建立连接时,用户的默认数据库名。
password nvarchar(128) 用户的加密密码(可以是 NULL)。
language nvarchar(128) 用户的默认语言。
denylogin int 如果登录是 Microsoft? Windows NT? 用户或组且已被拒绝访问,则为 1。
hasaccess int 如果已授权登录访问服务器,则为 1。
isntname int 如果登录是 Windows NT 用户或组,则为 1;如果登录是 Microsoft SQL Server? 登录,则为 0。
isntgroup int 如果登录是 Windows NT 组,则为 1。
isntuser int 如果登录是 Windows NT 用户,则为 1。
sysadmin int 如果登录是 sysadmin 服务器角色成员,则为 1。
securityadmin int 如果登录是 securityadmin 服务器角色成员,则为 1。
serveradmin int 如果登录是 serveradmin 固定服务器角色成员,则为 1。
setupadmin int 如果登录是 setupadmin 固定服务器角色成员,则为 1。
processadmin int 如果登录是 processadmin 固定服务器角色成员,则为 1。
diskadmin int 如果登录是 diskadmin 固定服务器角色成员,则为 1。
dbcreator int 如果登录是 dbcreator 固定服务器角色成员,则为 1。
loginname nvarchar(128) 登录的实际名称,该名称可能不同于 SQL Server 所使用的登录名。

sysoledbusers 页首

每个指定的链接服务器的用户和密码映射在表中占一行。该表存储在 master 数据库中。

列名 数据类型 描述
rmtsrvid smallint 服务器的 SID(安全标识号)。
rmtloginame nvarchar(128) loginsid 映射到的链接 rmtservid 的远程登录名。
rmtpassword nvarchar(128) 链接 rmtsrvid 内的指定远程登录的加密密码。
loginsid varbinary(85) 要映射的本地登录 SID。
status smallint 如果该值为 1,映射应使用用户自己的凭据。
changedate datetime 上次更改映射信息的日期。

sysprocesses  页首

sysprocesses 表中保存关于运行在 Microsoft? SQL Server? 上的进程的信息。这些进程可以是客户端进程或系统进程。 sysprocesses 只存储在 master 数据库中。

列名 数据类型 描述
spid smallint SQL Server 进程 ID。
kpid smallint Microsoft Windows NT 4.0? 线程 ID。
blocked smallint 分块进程的进程 ID ( spid )。
waittype binary(2) 保留。
waittime int 当前等待时间(以毫秒为单位)。当进程不处于等待时,为 0。
lastwaittype nchar(32) 表示上次或当前等待类型名称的字符串。
waitresource nchar(32) 锁资源的文本化表示法。
dbid smallint 当前正由进程使用的数据库 ID。
uid smallint 执行命令的用户 ID。
cpu int 进程的累计 CPU 时间。无论 SET STATISTICS TIME ON 选项是 ON 还是 OFF,都为所有进程更新该条目。
physical_io int 进程的累计磁盘读取和写入。
memusage int 当前分配给该进程的过程高速缓存中的页数。一个负数,表示进程正在释放由另一个进程分配的内存。
login_time datetime 客户端进程登录到服务器的时间。对于系统进程,是存储 SQL Server 启动发生的时间。
last_batch datetime 客户端进程上次执行远程存储过程调用或 EXECUTE 语句的时间。对于系统进程,是存储 SQL Server 启动发生的时间。
ecid smallint 用于唯一标识代表单个进程进行操作的子线程的执行上下文 ID。
open_tran smallint 进程的打开事务数。
status nchar(30) 进程 ID 状态(如运行、休眠等)。
sid binary(85) 用户的全局唯一标识符 (GUID)。
hostname nchar(128) 工作站的名称。
program_name nchar(128) 应用程序的名称。
hostprocess nchar(8) 工作站进程 ID 号。
cmd nchar(16) 当前正在执行的命令。
nt_domain nchar(128) 客户端的 Windows NT 4.0 域(如果使用 Windows 身份验证)或信任连接的 Windows NT 4.0 域。
nt_username nchar(128) 进程的 Windows NT 4.0用户名(如果使用 Windows 身份验证)或信任连接的 Windows NT 4.0 用户名。
net_address nchar(12) 指派给每个用户工作站上的网络接口卡唯一标识符。当用户登录时,该标识符插入 net_address 列。
net_library nchar(12) 用于存储客户端网络库的列。每个客户端进程都在网络连接上进入。网络连接有一个与这些进程关联的网络库,该网络库使得这些进程可以建立连接。有关更多信息,请参见客户端和服务器 Net-Library
loginame nchar(128) 登录名。

sysremotelogins 页首

每个允许调用 Microsoft? SQL Server? 上的远程存储过程的远程用户占一行。

列名 数据类型 描述
remoteserverid smallint 远程服务器标识。
remoteusername nvarchar(128) 远程服务器上的用户登录名。
status smallint 选项的位图。
sid varbinary(85) Microsoft Windows NT? 用户安全 ID。
changedate datetime 添加远程用户的日期和时间。

syscolumns 页首

每个表和视图中的每列在表中占一行,存储过程中的每个参数在表中也占一行。该表位于每个数据库中。

列名 数据类型 描述
name sysname 列名或过程参数的名称。
id int 该列所属的表对象 ID,或与该参数关联的存储过程 ID。
xtype tinyint systypes 中的物理存储类型。
typestat tinyint 仅限内部使用。
xusertype smallint 扩展的用户定义数据类型 ID。
length smallint systypes 中的最大物理存储长度。
xprec tinyint 仅限内部使用。
xscale tinyint 仅限内部使用。
colid smallint 列或参数 ID。
xoffset smallint 仅限内部使用。
bitpos tinyint 仅限内部使用。
reserved tinyint 仅限内部使用。
colstat smallint 仅限内部使用。
cdefault int 该列的默认值 ID。
domain int 该列的规则或 CHECK 约束 ID。
number smallint 过程分组时(0 表示非过程项)的子过程号。
colorder smallint 仅限内部使用。
autoval varbinary(255) 仅限内部使用。
offset smallint 该列所在行的偏移量;如果为负,表示可变长度行。
status tinyint 用于描述列或参数属性的位图:

0x08 = 列允许空值。
0x10 = 当添加 varcharvarbinary 列时,ANSI 填充生效。保留 varchar 列的尾随空格,保留 varbinary 列的尾随零。
0x40 = 参数为 OUTPUT 参数。
0x80 = 列为标识列。

type tinyint systypes 中的物理存储类型。
usertype smallint systypes 中的用户定义数据类型 ID。
printfmt varchar(255) 仅限内部使用。
prec smallint 该列的精度级别。
scale int 该列的小数位数。
iscomputed int 表示是否已计算该列的标志:

0 = 未计算。
1 = 已计算。

isoutparam int 表示该过程参数是否是输出参数:

1 = 真。
0 = 假。

isnullable int 表示该列是否允许空值:

1 = 真。
0 = 假。

sysconstraints 页首

包含约束映射,映射到拥有该约束的对象。该系统目录存储在每个数据库中。

列名 数据类型 描述
constid int 约束号。
id int 拥有该约束的表 ID。
colid smallint 在其上定义约束的列 ID,如果是表约束则为 0。
spare1 tinyint 保留。
status int 位图指示状态。可能的值包括:

1 = PRIMARY KEY 约束。
2 = UNIQUE KEY 约束。
3 = FOREIGN KEY 约束。
4 = CHECK 约束。
5 = DEFAULT 约束。
16 = 列级约束。
32 = 表级约束。

actions int 保留。
error int 保留。

sysfilegroups 页首

数据库中的每个文件组在表中占一行。该表存储在每个数据库中。在该表中至少有一项用于主文件组。

列名 数据类型 描述
groupid smallint 每个数据库的唯一组标识号。
allocpolicy smallint 保留。
status int 0x8 = READ ONLY
0x10 = DEFAULT
groupname sysname 文件组的名称。

sysfiles 页首

数据库中的每个文件在表中占一行。该系统表是虚拟表,不能直接更新或修改。

列名 数据类型 描述
fileid smallint 每个数据库的唯一文件标识号。
groupid smallint 文件组标识号。
size int 文件大小(以 8 KB 页为单位)。
maxsize int 最大文件大小(以 8 KB 页为单位)。0 值表示不增长,–1 值表示文件应一直增长到磁盘已满。
growth int 数据库的增长大小。0 值表示不增长。根据状态的值,可以是页数或文件大小的百分比。如果 status 包含 0x100000,则 growth 是文件大小的百分比;否则,它是页数。
status int growth 值(以兆字节 (MB) 或千字节 (KB) 为单位)的状态位。

0x1 = 默认设备。
0x2 = 磁盘文件。
0x40 = 日志设备。
0x80 = 自上次备份后已写入文件。
0x4000 = 由 Create DATABASE 语句
隐性创建的设备。
0x8000 = 在数据库创建过程中创建的设备。
0x100000 = 按百分比而不是按页数增长。

perf int 保留。
name nchar(128) 文件的逻辑名称。
filename nchar(260) 物理设备的名称,包括文件的完整路径。

sysforeignkeys 页首

包含关于表定义中的 FOREIGN KEY 约束的信息。该表存储在每个数据库中。

列名 数据类型 描述
constid int FOREIGN KEY 约束的 ID。
fkeyid int 具有 FOREIGN KEY 约束的表对象 ID。
rkeyid int 在 FOREIGN KEY 约束中引用的表对象 ID。
fkey smallint 正在引用的列 ID。
rkey smallint 已引用的列 ID。
keyno smallint 该列在引用列列表中的位置。

sysindexes 页首

数据库中的每个索引和表在表中各占一行。该表存储在每个数据库中。

列名 数据类型 描述
id int 表 ID(如果 indid = 0 或 255)。否则为索引所属表的 ID。
status int 内部系统状态信息。
first binary(6) 指向第一页或根页的指针。
indid smallint 索引 ID:

1 = 聚集索引
>1 = 非聚集
255 = 具有 text image 数据的表条目

root binary(6) 如果 indid >= 1 和 < 255, root 是指向根页的指针。如果 indid = 0 或 indid = 255, root 是指向最后一页的指针。
minlen smallint 最小行大小。
keycnt smallint 键的数目。
groupid smallint 在其上创建对象的文件组 ID。
dpages int 如果 indid = 0 或 indid = 1, dpages 是已用数据页的计数。如果 indid = 255,其设置为 0。否则是已用索引页的计数。
reserved int 如果 indid = 0 或 indid = 1, reserved 是分配给所有索引和表数据的页计数。如果 indid = 255, reserved 是分配给 textimage 数据的页计数。否则是分配给索引的页计数。
used int 如果 indid = 0 或 indid = 1, used 是用于所有索引和表数据的总页数。如果 indid = 255, used 是用于 textimage 数据的页计数。否则是用于索引的页计数。
rowcnt bigint 基于 indid = 0 和 indid = 1 的数据级行计数。如果 indid = 255, rowcnt 设置为 0。
rowmodctr int 对自上次更新表的统计后插入、删除或更新行的总数进行计数。
xmaxlen smallint 最大行大小。
maxirow smallint 最大非叶索引行大小。
OrigFillFactor tinyint 创建索引时使用的起始填充因子值。不保留该值;然而,如果需要重新创建索引但记不住当初使用的填充因子,则该值可能很有帮助。
reserved1 tinyint 保留。
reserved2 int 保留。
FirstIAM binary(6) 保留。
impid smallint 保留。索引实现标志。
lockflags smallint 用于约束经过考虑的索引锁粒度。例如,对于本质上是只读的查找表,可以将其设置为仅进行表级锁定以使锁定成本减到最小。
pgmodctr int 保留。
keys varbinary(816) 组成索引键的列 ID 列表。
name sysname 表名(如果 indid = 0 或 255)。否则为索引的名称。
statblob image 统计 BLOB。
maxlen int 保留。
rows int 基于 indid = 0 和 indid = 1的数据级行数,该值对于 indid >1 重复。如果 indid = 255, rows 设置为 0。提供该列是为了向后兼容。

sysmembers  页首

每个数据库角色成员在表中占一行。该表存储在每个数据库中。

列名 数据类型 描述
memberuid smallint 角色成员的用户 ID。
groupuid smallint 角色的用户 ID。

sysobjects 页首

在数据库内创建的每个对象(约束、默认值、日志、规则、存储过程等)在表中占一行。只有在 tempdb 内,每个临时对象才在该表中占一行。

列名 数据类型 描述
name sysname 对象名。
Id int 对象标识号。
xtype char(2) 对象类型。可以是下列对象类型中的一种:

C = CHECK 约束
D = 默认值或 DEFAULT 约束
F = FOREIGN KEY 约束
L = 日志
FN = 标量函数
IF = 内嵌表函数
P = 存储过程
PK = PRIMARY KEY 约束(类型是 K)
RF = 复制筛选存储过程
S = 系统表
TF = 表函数
TR = 触发器
U = 用户表
UQ = UNIQUE 约束(类型是 K)
V = 视图
X = 扩展存储过程

uid smallint 所有者对象的用户 ID。
info smallint 保留。仅限内部使用。
status int 保留。仅限内部使用。
base_schema_
ver
int 保留。仅限内部使用。
replinfo int 保留。供复制使用。
parent_obj int 父对象的对象标识号(例如,对于触发器或约束,该标识号为表 ID)。
crdate datetime 对象的创建日期。
ftcatid smallint 为全文索引注册的所有用户表的全文目录标识符,对于没有注册的所有用户表则为 0。
schema_ver int 版本号,该版本号在每次表的架构更改时都增加。
stats_schema_
ver
int 保留。仅限内部使用。
type char(2) 对象类型。可以是下列值之一:

C = CHECK 约束
D = 默认值或 DEFAULT 约束
F = FOREIGN KEY 约束
FN = 标量函数
IF = 内嵌表函数
K = PRIMARY KEY 或 UNIQUE 约束
L = 日志
P = 存储过程
R = 规则
RF = 复制筛选存储过程
S = 系统表
TF = 表函数
TR = 触发器
U = 用户表
V = 视图
X = 扩展存储过程

userstat smallint 保留。
sysstat smallint 内部状态信息。
indexdel smallint 保留。
refdate datetime 留作以后使用。
version int 留作以后使用。
deltrig int 保留。
instrig int 保留。
updtrig int 保留。
seltrig int 保留。
category int 用于发布、约束和标识。
cache smallint 保留。

syspermissions  页首

包含有关对数据库内的用户、组和角色授予和拒绝的权限的信息。该表存储在每个数据库中。

列名 数据类型 描述
id int 对象权限的对象 ID;0 表示语句权限。
grantee smallint 受权限影响的用户、组或角色的 ID。
grantor smallint 被授予或废除权限的用户、组或角色的 ID。
actadd smallint 仅限内部使用。
actmod smallint 仅限内部使用。
seladd varbinary(4000) 仅限内部使用。
selmod varbinary(4000) 仅限内部使用。
updadd varbinary(4000) 仅限内部使用。
updmod varbinary(4000) 仅限内部使用。
refadd varbinary(4000) 仅限内部使用。
refmod varbinary(4000) 仅限内部使用。

systypes  页首

对于每种系统提供数据类型和用户定义数据类型,均包含一行信息。该表存储在每个数据库中。

这些是系统提供的数据类型及其 ID 号。

列名 数据类型 描述
name sysname 数据类型名称。
xtype tinyint 物理存储类型。
status tinyint 仅限内部使用。
xusertype smallint 扩展用户类型。
length smallint 数据类型的物理长度。
xprec tinyint 服务器所使用的内部精度。(不能在查询中使用。)
xscale tinyint 服务器所使用的内部小数位数。(不能在查询中使用。)
tdefault int 对此数据类型进行完整性检查的存储过程的 ID。
domain int 对此数据类型进行完整性检查的存储过程的 ID。
uid smallint 数据类型创建者的用户 ID。
reserved smallint 仅限内部使用。
usertype smallint 用户类型 ID。
variable bit 可变长度数据类型为 1;否则为 0。
allownulls bit 指出此数据类型的默认为空性。如果 Create 或 Alter TABLE 指定了为空性,那么该值将替代此数据类型的默认为空性。
type tinyint 物理存储数据类型。
printfmt varchar(255) 保留。
prec smallint 此数据类型的精度级别。
scale tinyint 此数据类型的小数位数(根据精度)。

sysusers 页首

数据库中每个 Microsoft? Windows 用户、Windows 组、Microsoft SQL Server? 用户或 SQL Server 角色在表中占一行。

列名 数据类型 描述
uid smallint 用户 ID,在此数据库中是唯一的。1 是数据库所有者。
status smallint 仅限内部使用。
Name sysname 用户名或组名,在此数据库中是唯一的。
sid varbinary(85) 此条目的安全性标识符。
roles varbinary(2048) 仅限内部使用。
createdate datetime 帐户的添加日期。
updatedate datetime 帐户的上次修改日期。
altuid smallint 仅限内部使用。
password varbinary(256) 仅限内部使用。
gid smallint 此用户所属的组 ID。如果 uid = gid ,那么此条目就定义一个组。
environ varchar(255) 保留。
hasdbaccess int 如果该帐户有数据库访问权限,则为 1。
islogin int 如果该帐户是有登录帐户的 Windows 组、Windows 用户或 SQL Server 用户,则为 1。
isntname int 如果该帐户是 Windows 组或 Windows 用户,则为 1。
isntgroup int 如果该帐户是 Windows 组,则为 1。
isntuser int 如果该帐户是 Windows 用户,则为 1。
issqluser int 如果该帐户是 SQL Server 用户,则为 1。
isaliased int 如果该帐户以另一个用户为别名,则为 1。
issqlrole int 如果该帐户是 SQL Server 角色,则为 1。
isapprole int 如果该帐户是应用程序角色,则为 1。

[教程]ADO.Net2.0架构

mikel阅读(953)

ADO.NET 2.0 中的架构

发布日期 : 09/19/2004 | 更新日期 : 09/19/2004

Bob Beauchemin
DevelopMentor

适用于:
Microsoft ADO.NET 2.0
Microsoft Visual Studio 2005
C# 编程语言

摘要:了解在 ADO.NET 中对于从您的数据源访问元数据的增强支持。

下载相关的 SchemasSample.exe 示例代码。

本页内容

深入了解新的公共元数据 API 深入了解新的公共元数据 API
究竟谁需要元数据? 究竟谁需要元数据?
我能得到什么样的元数据? 我能得到什么样的元数据?
Restrictions Restrictions
DataSourceInformation DataSourceInformation
自定义并扩展元数据 自定义并扩展元数据
用户自定义 用户自定义
小结:元数据支持的最终部分 小结:元数据支持的最终部分

深入了解新的公共元数据 API

我的前一篇文章, 我指出 Visual Studio 2005 服务器资源管理器现在使用一个包含了 .NET 数据提供程序(而不是 OLE DB 提供程序)列表的对话框来提示连接信息。当您确定一个连接字符串并添加数据连接时,每个数据连接也显示一个关于通过连接直接可见的数据库对象(如表、视图 和存储过程)的信息的树形结构。但这些信息来自哪里呢?难道是 Visual Studio 仅为某些数据提供程序硬编码来生成这个信息,而假如我编写我自己的数据提供程序或者从第三方购买一个的时候,就留给我一个空节点?不,在 Visual Studio 2005 中并不是这样。由于 ADO.NET 2.0 中的新架构 API,所有这些有用的信息都将提供给您。我不知道这是否是 Visual Studio 做到它的方法,但是这里就是使用新的 API 来获得一个数据库中的表的列表的代码。

// uses a ADO.NET 2.0 named connection string in config file
// uses ADO.NET 2.0 ProviderFactory and base classes
// see previous article
public static void GetListOfTables(string connectstring_name)
{
ConnectionStringSettings s =
ConfigurationSettings.ConnectionStrings[connectstring_name];
DbProviderFactory f = DbProviderFactories.GetFactory(s.ProviderName);
using (DbConnection conn = f.CreateConnection())
{
conn.ConnectionString = s.ConnectionString;
conn.Open();
DataTable t = conn.GetSchema("Tables");
t.WriteXml("tables.xml");
}
}

究竟谁需要元数据?

元 数据是每个数据访问 API 的一部分。尽管元数据的主要使用者是像 Visual Studio 这样的工具或者像 DeKlarit 这样的代码生成器,但是它们并不是惟一的使用者。应用程序包设计师可能允许最终用户通过向现有的表添加新表或新列来自定义一个应用程序。当最终用户如此改 变了数据库架构时,一个通用查询和修改工具可以在维护、备份和其他应用程序函数中使用元数据来包含用户的新表,就像它们是应用程序附带的内置表一样。程序 员可以使用元数据来编写他们自己的派生自 System.Data.Common.DbCommandBuilder的自定义类,并为使用 DataSet 创建插入、更新和删除命令。多数据库应用程序(即设计为在用户选择的数据库上运行的应用程序)的构建者可以尽可能多地使用元数据来维护公共代码库,在需要时优化数据访问代码。

通过一般元数据 API 来公开元数据要比让每个使用者使用特定于数据库的 API 要好。这样,工具编写人员可以维护一个可管理性更好的代码库。这样的 API 还必须是非常灵活的,因为在编写一般 API 来公开元数据时有四个障碍需要考虑。

  1. 元数据集合和信息在数据库间是有差别的。例如,SQL Server 用户可能想要公开一个链接服务器的集合,但是 oracle 用户可能对关于 oracle 序列的信息感兴趣。

  2. 不仅在不同的数据库产品中,而且即使在相同数据库的不同版本中,存储公共数据库元数据的基础系统表都是不同的。例如,SQL Server 2005 使用在一个“sys”架构下的新表(例如,sys.tables)公开它的元数据,而 SQL Server 以前的版本使用元数据表(如 sysobjects£©来存储相同的数据。

  3. 不同的程序可能有不同的元数据视图。以一个例子来说,许多程序员抱怨 oracle 数据库中表的列表太长,因为大多数元数据 API 将“system”表与用户表混在一起。他们想要一个仅由他们定义的表组成的短列表。

  4. 是否根本不支持元数据,要提供多少元数据,应该完全取决于提供程序的编写者。

大 部分数据库 API 提供一个标准的元数据集,它是所有提供程序必须支持的,并且允许提供程序编写者添加新的元数据表。这与使用 ANSI SQL 标准采用的方法是一致的。解决这一问题的标准的一部分是 Schema Schemata(INFORMATION_SCHEMA 和 DEFINITION_SCHEMA)的第 11 部分。ANSI SQL INFORMATION_SCHEMA 定义了由一个兼容的数据库支持的标准的元数据视图集。但即便是这个规范也需要有一个方法来解决上面这些问题。它声明:

“实施者可以自由添加额外的表到 INFORMATION_SCHEMA 或添加额外的列到预定义的INFORMATION_SCHEMA 表。”

OLE DB 作为一个与 ANSI SQL 标准概念一致的数据访问 API 示例,定义了一系列的名为“架构行集合”的元数据。它从一个大致遵循 INFORMATION_SCHEMA 的预定义集开始,并添加 OLE DB 特定的列到每个行中。ADO.NET 2.0 提供了一个甚至更强大更灵活的机制来公开元数据。

我能得到什么样的元数据?

ADO.NET 2.0 允许提供程序编写者公开 5 种不同类型的元数据。这些主要的元数据 — “元数据集合”或“类别” — 在 System.Data.Common.DbMetaDataCollectionNames 类中被枚举出来。

  • MetaDataCollections — 可用元数据集合的列表。

  • Restrictions — 对于每个元数据集合,存在一批可以用于限制被请求的架构信息范围的限定符。

  • DataSourceInformation — 关于数据提供程序引用的数据库实例的信息。

  • DataTypes — 一组关于数据库支持的每个数据类型的信息。

  • ReservedWords — 适用于该种数据库查询语言的保留字。通常“查询语言”等同于一种 SQL 的方言。

MetaDataCollections 是 INFORMATION_SCHEMA 集合的名称,如“表”、“列”或“主键”。但是,如果使用 DbConnection.GetSchema,这些元数据类别也被认为是元数据。这意味着在代码方面来说是这样,这些集合可以像普通的元数据一样被获得。

// gets information about database Views
Table t1 = conn.GetSchema("Views");
// gets information about collections exposed by this provider
// this includes the five "meta-collections" described above
Table t2 = conn.GetSchema(DbMetaDataCollectionNames.MetaDataCollections);
// gets information about the Restrictions meta-collection
Table t3 = conn.GetSchema(DbMetaDataCollectionNames.Restrictions);
// No argument overload is same as asking for MetaDataCollections
Table t4 = conn.GetSchema();

5 个元数据集合中的 2 个值得进一步解释。

Restrictions

Restrictions 可以用来限制返回元数据的数量。如果您熟悉 OLE DB 或 ADO,那么术语“restriction”意味着在那些 API 中同样的内容。作为示例,让我们使用 MetaDataCollection“列”,它是表中的列名称的集合。这个集合可以用于获取所有表中的所有列。但是,此被请求的列集合会被数据库名称、 所有者/架构或者表限制。每个元数据集合可以有不同数量的可能限制,并且每个限制会有一个默认值。在我们下面的示例中,这里是一个对列元数据的限制的 XML 表示:

清单 1. 列集合上的 Restrictions(XML 格式)

<Restrictions>
<CollectionName>Columns</CollectionName>
<RestrictionName>Catalog</RestrictionName>
<RestrictionDefault>table_catalog</RestrictionDefault>
<RestrictionNumber>1</RestrictionNumber>
</Restrictions> <Restrictions>
<CollectionName>Columns</CollectionName>
<RestrictionName>Owner</RestrictionName>
<RestrictionDefault>table_schema</RestrictionDefault>
<RestrictionNumber>2</RestrictionNumber>
</Restrictions> <Restrictions>
<CollectionName>Columns</CollectionName>
<RestrictionName>Table</RestrictionName>
<RestrictionDefault>table_name</RestrictionDefault>
<RestrictionNumber>3</RestrictionNumber>
</Restrictions> <Restrictions>
<CollectionName>Columns</CollectionName>
<RestrictionName>Column</RestrictionName>
<RestrictionDefault>column_name</RestrictionDefault>
<RestrictionNumber>4</RestrictionNumber>
</Restrictions>

Restrictions 是使用一个重载的 DbConnection.GetSchema 指定的。这些限制被指定为一个数组。您可以将一个数组指定为和整个限制集合或者一个子集数组一样大,因为“RestrictionNumbers”通常从 最少限制向最多限制发展。对您想要省略的限制值使用空值(不是数据库 NULL,而是 .NET NULL,或者在 Visual Basic .NET 中的 Nothing)。例如:

// restriction string array
string[] res = new string[4];
// all columns, all tables owned by dbo
res[1] = "dbo";
DataTable t1 = conn.GetSchema("Columns", res);
// clear collection
for (int i = 0; i < 4; i++) res[i] = null;
// all columns, all tables named "authors", any owner/schema
res[2] = "authors";
DataTable t2 = conn.GetSchema("Columns", res);
// clear collection
for (int i = 0; i < 4; i++) res[i] = null;
// columns named au_lname
// all tables named "authors", any owner/schema
res[2] = "authors";  res[3] = "au_lname";
DataTable t3 = conn.GetSchema("Columns", res);
// clear collection
for (int i = 0; i < 4; i++) res[i] = null;
// columns named au_lname
// any tables, any owner/schema
res[3] = "name";
DataTable t4 = conn.GetSchema("Columns", res);

您无需指定整个限制数组。在上面的情况中,这里您只想看到“dbo”拥有的表中的列,您可以指定一个只带有两个而不是全部四个成员的 数组。也请注意,将一个空字符串指定为一个限制与指定一个 null(在 Visual Basic .NET 中为 Nothing)值是不同的。您不必记住这些限制,您始终可以查询它们,就像任何其他集合一样。“Restrictions”集合本身不允许限制,但是因 为信息被提取到 DataTable 中,所以您可以使用一个 DataView 来提供相似的功能,如下所示。

DataTable tv = conn.GetSchema(DbMetaDataCollectionNames.Restrictions);
DataView v = tv.DefaultView;
// show restrictions on the "Columns" collection, sorted by number
v.RowFilter = "CollectionName = 'Columns'";
v.Sort = "RestrictionNumber";
for (int i = 0; i < tv.Count; i++)
Console.WriteLine("{0} (default){1}",
tv.Rows[i]["RestrictionName"],
tv.Rows[i]["RestrictionDefault"]);

DataSourceInformation

DataSourceInformation 集合为查询生成器提供关于当前数据库(数据源)实例的信息。虽然这个集合可包含提供程序需要的任何内容,但在 Microsoft 提供程序 (SqlClient、OracleClient、OleDb、Odbc) 中,这个集合包含相似的信息。这里是您默认获得的信息。

表 1. 在 Microsoft 提供程序中的 DataSourceInformation

格式/意义

CompositeIdentifierSeparatorPattern

多部分名称的分隔符(如 pubs.dbo.authors 中的点)

DataSourceProductName

数据库名称

DataSourceProductVersion

数据库版本。请注意这是当前通过 DbConnection 访问的数据库实例的版本。

DataSourceProductVersionNormalized

?

GroupByBehavior

枚举,System.Data.Common.GroupByBehavior

IdentifierPattern

正则表达式字符串

IdentifierCase

枚举,System.Data.Common.IdentifierCase

OrderByColumnsInSelect

布尔值,默认情况下您应该在一个 Select 语句中 orDER BY 这些列

ParameterMarkerFormat

说明参数标记是否以一个特殊的字符开始(如 T-SQL 中的 @)

ParameterMarkerPattern

用于创建参数的正则表达式字符串

ParameterNameMaxLength

参数的最大长度

ParameterNamePattern

用于创建参数的正则表达式字符串

QuotedIdentifierPattern

用于引用标识符的正则表达式字符串

QuotedIdentifierCase

枚举,System.Data.Common.IdentifierCase

StatementSeparatorPattern

正则表达式字符串

StringLiteralPattern

正则表达式字符串

SupportedJoinOperators

枚举,System.Data.Common.SupportedJoinOperators

对特定的数据库方言来说有太多的信息来产生 SQL 了,您不这样认为么?还有一条信息我想要说一下,那就是提供程序是否在参数化查询中使用命名参数或者位置参数。在我关于编写独立于提供程序的代码的上一篇文章中,我将命名和位置参数作为编写参数化命令的两种方法来讨论。

自定义并扩展元数据

既 然我们已经看到了提供的基础元数据并且可以围绕 DbConnection.GetSchema() 找到我们的方法,让我们讨论提供程序编写者使用简单的声明性格式自定义元数据的方法,以及程序员如何能够挂钩到那种格式中。这个讨论与文章开始的元数据复 杂性相关:如何提供独立于数据库版本的元数据以及如何处理不同使用者可能需要相同元数据的不同视图的事实。

首先,让我们指出元数据支持完全是可选的。提供程序不必支持 DbConnection.GetSchema, 这种方法会引发 NotSupportedException。此外,如果提供程序编写者选择支持 DbConnection.GetSchema,只有 MetaDataCollections 类别是必需的。提供程序可以选择不提供任何或所有其他 4 个类别的信息。

其次,每个提供程序可以公开相同元数据集合的不同信息。例如,Tables 集合的结构完全取决于提供程序编写者。举个例子,SqlClient 提供程序在 Tables 集合中公开了 4 个信息项:table_catalog、table_schema、table_name 和 table_type。OracleClient 提供程序仅公开了 3 个信息项(OWNER、TABLE_NAME 和 TYPE),因为 oracle 数据库不包含多种目录。对每个提供程序来说限制和限制项的数量可以是不同的。再次以表的情况为例,SqlClient 提供程序支持 4 个限制,而 oracleClient 提供程序只支持 2 个。限制也不必按照任何指定的顺序发生。所以与在 OLE DB 和 ODBC API 中不同,这里没有委托管理的元数据结构、大量元数据或者元数据顺序。提供程序可以自由公开任何相关的元数据。但是,如果一个特定的应用程序(如 Visual Studio)要求在一个应用程序里使用的所有 .NET 数据提供程序中元数据是一致的,它也能够通过覆盖提供程序的标准行为来获得这个行为。我们将在后面的用户自定义小节进一步讨论这个问题。

提供程序编写者可以将元数据逻辑直接硬编码到他们的提供程序中,每个提供程序编写者为了获得相似的元数据可以使用不同的内部算法。例如,在实现 OLE DB 的 ISchemaRowset 方法时,这就是过去完成它的方法。但是,在 ADO.NET 2.0 中,在 System.Data.ProviderBase 命名空间中有一些基类是提供程序编写者可用的。4 个可用的 Microsoft 提供程序使用这些基类,因此它们都以相似的方法实现架构。我将用这个实现进行讲解,希望大多数编写提供程序的程序员喜欢 DataDirect 技术,而其他提供程序编写者也使用它。

公开元数据的基类是 DbMetaDataFactory。 实现它的一个子类的提供程序使用一个 XML 文件来定义其元数据提取行为。这些文件是在 System.Data.dll 和 System.Data.OracleClient.dll 中嵌入的资源,您可以通过从命令行运行 ILDASM.exe 来查看原始的 XML 文件。

>ildasm.exe System.Data.dll /out:dummy.il

查看从 ILDASM 生成的 XML 资源文件,如同剥开了洋葱的另一层。这个文件枚举了被支持的集合以及包含在每个元数据集合(通过架构)中的信息,并且看起来是使用 DataSet.WriteXml(XmlWriteMode.WriteSchema) 重载的 DataSet.WriteXml 方法的输出。最有趣的部分是在除了 DataSourceInformation 和 MetaDataCollections 元素中的 PopulationMechanism/PopulationString 子元素以外的所有元数据集合中的 MinimumVersion/MaximumVersion 元素。

使 用 MinimumVersion/MaximumVersion 允许提供程序编写者指定对于不同版本的数据库要执行哪些元数据查询。通过使用单个 MetaDataCollection 的多个元素,您可以使 GetSchema 对不同版本的数据库表现不同。举一个明显的例子,您可以使用与以前版本的 SQL Server 不同的 SQL Server 2005 各版本。这里是一个使用来自 SQL Server 元数据资源 (System.Data.SqlClient.SqlMetaData) 的 MinimumVersion 的例子:

清单 2. 数据类型集合中的数据类型 XML 的元数据项

<DataTypes>
<TypeName>xml</TypeName>
<ProviderDbType>25</ProviderDbType>
<ColumnSize>2147483647</ColumnSize>
<DataType>System.String</DataType>
<IsAutoIncrementable>false</IsAutoIncrementable>
<IsCaseSensitive>false</IsCaseSensitive>
<IsFixedLength>false</IsFixedLength>
<IsFixedPrecisionScale>false</IsFixedPrecisionScale>
<IsLong>true</IsLong>
<IsNullable>true</IsNullable>
<IsSearchable>true</IsSearchable>
<IsSearchableWithLike>false</IsSearchableWithLike>
<MinimumVersion>09.00.000.0</MinimumVersion>
<IsLiteralSupported>false</IsLiteralSupported>
</DataTypes>

这定义了关于 SQL Server 数据类型 XML 的信息。MinimumVersion 指示出,这个数据类型只在使用 SQL Server 2005 时可用。如果您要求 SqlConnection.GetSchema 提供数据库支持的数据类型列表,只有 SQL Server 2005 的各版本数据库(SQL Server 2005 是版本 9,当前的beta 2 版是 09.00.852.2)会报告它们支持 XML 数据类型。

对于通常被 INFORMATION_SCHEMA(如表、视图或存储过程)公开的集合,PopulationMechanism 和 PopulationString 是工作开始的地方。在这个实现中使用了三个 PopulationMechanisms:DataTableSQLCommandPrepareCollection。DataTable 用于填充元数据集合。使用 DataTable 意味着用于填充集合的信息是在 XML 资源文件本身当中。在每种情况下,PopulationString 是当 XML 资源文件加载到一个 .NET DataSet 时,生成的 DataTable 的名称。SQLCommand 意味着提供程序将使用一个 DbCommand 实例来发出对数据库的命令。如果您查看由 SQLCommand 产生的集合的一个 PopulationString:

清单 3. SQL Server 中的数据库(目录)项 — MetaDataCollection

<MetaDataCollections>
<CollectionName>Databases</CollectionName>
<NumberOfRestrictions>1</NumberOfRestrictions>
<NumberOfIdentifierParts>1</NumberOfIdentifierParts>
<PopulationMechanism>SQLCommand</PopulationMechanism>
<PopulationString>select name as database_name, dbid, crdate as create_date from master..sysdatabases where name = {0}</PopulationString>
</MetaDataCollections>

当限制在 DbConnection.GetSchema 中使用时,很容易就能够推断出字符串替换将被应用到“基查询”中。如果没有限制被指定,那么实际上该谓词将被剥离出查询。

当 PopulationMechanism 的值为 PrepareCommand 时,提供程序编写者可以使用自定义机制。有一个 DbMetaDataFactory 的 PrepareCommand 方法,如果它被提供程序编写者覆盖,就可以被编码来使用提供程序选择的任何自定义语义。这一机制被用在 SqlClient 中来生成 DataTypes 元数据集合。PrepareCommandSqlMetaDataFactory 子类实现首先从 DataTable 中读取由 SQL Server 支持的内置数据类型,如同用其他元数据集合一样;然后,如果数据库是 SQL Server 2005 的话,使用自定义逻辑来将用户定义的类型添加到集合中。(注:SQL Server 2005 可以将 .NET 类作为用户定义的类型公开。更多信息请参阅 A First Look at SQL Server 2005 for Developers 的第 5 章。)

用户自定义

除了提供程序自定义机制外,也有允许程序员在每个应用程序基础上自定义架构信息的挂钩!在加载嵌入资源之前,DbConnectionFactory CreateMetaDataFactory 将参考应用程序配置文件。每个提供程序都可以用任何它选择的方法实现 CreateMetaDataFactory 来为其 DbMetaDataFactory 获取 XML 流,但是那 4 个 Microsoft 提供程序遵循一个公共模式。每个 Microsoft 提供程序将查找一个按提供程序本身命名的应用程序配置设置(如 system.data.sqlclient)。在这个设置元素中您可以 添加或删除名值对。DbMetaDataFactory 查找一个名称“MetaDataXml”。与特殊名称对应的值是一个文件的名称。这是一个简单的文件名 — 这个文件必须存在于 .NET 安装位置的 CONFIG 子目录中。这是 machine.config 和安全配置设置所在的目录。这个文件必须包含整个的架构配置信息集,而不仅仅是那些更改。

出于多个原因,对于支持此机制的提供程序, 您可以使用这个机制。例如,您可以更改 oracleClient 提供程序中的架构查询来使用“USER”目录视图而不是“ALL”目录视图。因为“USER”视图不包含关于内部数据库表的信息,例如,表列表将会短很多 并且更易于使用。另一个示例可能包括为所有的 .NET 数据提供程序编码输出元数据 XML 文件,这提供给您一致的标准元数据集,该元数据集可能正好符合 SQL-99 INFORMATION_SCHEMA 视图。这可能恰恰适合您的应用程序。

一个更具体的例子是,如果我想要公开 SQL Server 2005 中关于 SQL Server Service Broker 的元数据集合的信息。这些集合可以包括 QUEUE、SERVICE、CONTRACT 和消息类型。我会从嵌入的 XML 资源文件开始并用我的新集合上的信息修饰它。如果这个文件的名称是 SQLBrokerAware.xml,我会安装这个文件,我的应用程序配置文件将为如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.data.sqlclient>
<settings>
<add name="MetaDataXml" value="SQLBrokerAware.xml">
</add>
</settings>
</system.data.sqlclient>
</configuration>

这就是所有的步骤。使用这个设置,我可以编写代码 — 在其中 Service Broker 元数据是可用于客户端的内置元数据的组成部分。对所有队列来说,代码可能如下所示:

using (SqlConnection conn = new SqlConnection(connstring))
{
conn.Open();
// this includes Service Broker metadata collections
Table t = conn.GetSchema(DbMetaDataCollectionNames.MetaDataCollections);
// get all the queues in my database
Table queues = conn.GetSchema("Queues");
}

真是非常酷!本文包含一个添加 Service Broker 元数据的代码示例。 尽管这是一个非常强大的功能,它还是有可能被滥用的。请记住您需要将元数据 XML 文件分发到每个使用它的应用程序,并说服系统管理员为您将其安装在 CONFIG 目录中。而且您需要用发布的提供程序的每个新版本来维护它。因为使用一般元数据 API 的理由之一是可拥有跨数据库和应用程序的一致元数据,所以这个功能不应被无故使用。还需注意此时您不能提供 PrepareCommand 的自定义实现。

关于自定义的最后要注意的,您可能已经猜到了,自定义和资源对于 OLE DB 和 ODBC 的桥提供程序的使用是不同的。当您使用这些提供程序时,默认的 Odbc 或 OleDb XML 资源文件被使用,然后您不仅可以自定义主要的 Odbc 或 OleDb 架构行为,而且可以在每个提供程序基础上自定义行为。如果您想要指定自己的提供程序或者驱动程序,在添加/删除设置子元素中使用的名称属性不能是 MetaDataXml,而应该是 [providershortname]:MetaDataXml。如果您想让您的文件成为 OleDb 或 Odbc 数据提供程序的默认文件,您甚至可以指定 defaultMetaDataXml 的名称。

小结:元数据支持的最终部分

在结束前,我只想说说其他两个不是通过 DbConnection.GetSchema 公开的元数据扩展。 DbCommandBuilder 包含两个属性,QuoteIdentifierUnquoteIdentifier,它们允许您在由 CommandBuilder 生成的命令中自定义标识符。举个例子,根据您的会话设置,在 SQL Server 中您可以使用双引号 (") 或括号('[' 和 ']')来引用标识符。最后,在 System.Data.Sql 命名空间中的 SqlMetaData 类被用于公开 SQL Server DataReader 中的元数据并允许您在 SqlCommand 使用的 Parameters 中 设置这个元数据。虽然不是任何地方在细节上都非常接近,但是这个元数据在概念上与在 DataTypes 元数据集合中公开的元数据相似。SqlMetaData 对 SqlClient 数据提供程序和 SQL Server 2005 包括的 in-database SQLServer 数据提供程序都是适用的。SqlMetaData 增大了当前通过 SqlDataReader.GetSchemaTable() 方法公开的行集合元数据。

此 时您很可能同意 ADO.NET 2.0 元数据基础结构是您所见过的最强大、灵活和可自定义的结构。它将 ADO.NET 发展成为一个完全面向对象的数据库 API。工具供应商、提供程序编写者和 Visual Studio 数据工具用户将会高兴地在街上跳舞 — 我们那里见。

Bob Beauchemin,DevelopMentor 的讲师、课程作者和数据库课程联络员。作为以数据为中心的分布式系统的架构师、程序员和管理员,他有超过 25 年的经验。他一直为 Microsoft Systems Journal 和 SQL Server Magazine 等杂志撰写 ADO.NET、OLE DB 和 SQL Server 方面的文章,并且是 A First Look at SQL Server 2005 for Developers Essential ADO.NET 的作者。

转到原英文页面

[代码]某人封装的一个ADO.net操作类

mikel阅读(638)

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Runtime.Remoting.Messaging;
using System.Data;
using System.Data.SQLClient;
using System.Configuration;
namespace LTP.SQLServerDAL
{
///

/// ADO.NET数据库操作基础类。
///

public abstract class DbManagerSQL
{
//数据库连接字符串
protected static string connectionString = ConfigurationSettings.AppSettings[“ConnectionString”];
public DbManagerSQL()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
///

/// 执行SQL语句,返回影响的记录数
///

/// ///
public static int ExecuteSql(string SQLString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand(SQLString,connection))
{
try
{
connection.Open();
int rows=cmd.ExecuteNonQuery();
return rows;
}
catch(System.Data.SqlClient.SqlException E)
{
throw new Exception(E.Message);
}
}
}
}
///

/// 执行两条SQL语句,实现数据库事务。
///

/// /// public static void ExecuteSqlTran(string SQLString1,string SQLString2)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection=connection;
SqlTransaction tx=connection.BeginTransaction();
cmd.Transaction=tx;
try
{
cmd.CommandText=SQLString1;
cmd.ExecuteNonQuery();
cmd.CommandText=SQLString2;
cmd.ExecuteNonQuery();
tx.Commit();
}
catch(System.Data.SqlClient.SqlException E)
{
tx.Rollback();
throw new Exception(E.Message);
}
finally
{
cmd.Dispose();
connection.Close();
}
}
}
///

/// 执行多条SQL语句,实现数据库事务,每条语句以“;”分割。
///

/// public static void ExecuteSqlTran(string SQLStringList)
{
using (OdbcConnection conn = new OdbcConnection(connectionString))
{
conn.Open();
OdbcCommand cmd = new OdbcCommand();
cmd.Connection=conn;
OdbcTransaction tx=conn.BeginTransaction();
cmd.Transaction=tx;
try
{
string [] split= SQLStringList.Split(new Char [] { ';'});
foreach (string strsql in split)
{
if (strsql.Trim()!=””)
{
cmd.CommandText=strsql;
cmd.ExecuteNonQuery();
}
}
tx.Commit();
}
catch(System.Data.Odbc.OdbcException E)
{
tx.Rollback();
throw new Exception(E.Message);
}
}
}
///

/// 执行带一个存储过程参数的的SQL语句。
///

/// /// ///
public static int ExecuteSql(string SQLString,string content)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(SQLString,connection);
System.Data.SqlClient.SqlParameter myParameter = new System.Data.SqlClient.SqlParameter ( “@content”, SqlDbType.NText);
myParameter.Value = content ;
cmd.Parameters.Add(myParameter);
try
{
connection.Open();
int rows=cmd.ExecuteNonQuery();
return rows;
}
catch(System.Data.SqlClient.SqlException E)
{
throw new Exception(E.Message);
}
finally
{
cmd.Dispose();
connection.Close();
}
}
}
///

/// 向数据库里插入图像格式的字段
///

/// /// ///
public static int ExecuteSqlInsertImg(string strSQL,byte[] fs)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(strSQL,connection);
System.Data.SqlClient.SqlParameter myParameter = new System.Data.SqlClient.SqlParameter ( “@fs”, SqlDbType.Image);
myParameter.Value = fs ;
cmd.Parameters.Add(myParameter);
try
{
connection.Open();
int rows=cmd.ExecuteNonQuery();
return rows;
}
catch(System.Data.SqlClient.SqlException E)
{
throw new Exception(E.Message);
}
finally
{
cmd.Dispose();
connection.Close();
}
}
}
///

/// 执行一条计算查询结果语句,返回查询结果(整数)。
///

/// ///
public static int GetCount(string strSQL)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(strSQL,connection);
try
{
connection.Open();
SqlDataReader result = cmd.ExecuteReader();
int i=0;
while(result.Read())
{
i=result.GetInt32(0);
}
result.Close();
return i;
}
catch(System.Data.SqlClient.SqlException e)
{
throw new Exception(e.Message);
}
finally
{
cmd.Dispose();
connection.Close();
}
}
}
///

/// 执行一条计算查询结果语句,返回查询结果(object)。
///

/// ///
public static object GetSingle(string SQLString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(SQLString,connection);
try
{
connection.Open();
object obj = cmd.ExecuteScalar();
if((Object.Equals(obj,null))||(Object.Equals(obj,System.DBNull.Value)))
{
return null;
}
else
{
return obj;
}
}
catch(System.Data.SqlClient.SqlException e)
{
throw new Exception(e.Message);
}
finally
{
cmd.Dispose();
connection.Close();
}
}
}
///

/// 执行查询语句,返回SqlDataReader
///

/// ///
public static SqlDataReader ExecuteReader(string strSQL)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand(strSQL,connection);
SqlDataReader myReader;
try
{
connection.Open();
myReader = cmd.ExecuteReader();
return myReader;
}
catch(System.Data.SqlClient.SqlException e)
{
throw new Exception(e.Message);
}
finally
{
cmd.Dispose();
connection.Close();
}
}
}
///

/// 执行查询语句,返回DataSet
///

/// ///
public static DataSet Query(string SQLString)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet ds = new DataSet();
try
{
connection.Open();
SqlDataAdapter command = new SqlDataAdapter(SQLString,connection);
command.Fill(ds,”ds”);
}
catch(System.Data.SqlClient.SqlException ex)
{
throw new Exception(ex.Message);
}
return ds;
}
}
#region 存储过程操作
///

/// 运行存储过程
///

/// /// ///
public static SqlDataReader RunProcedure(string storedProcName, IDataParameter[] parameters )
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlDataReader returnReader;
connection.Open();
SqlCommand command = BuildQueryCommand( connection,storedProcName, parameters );
command.CommandType = CommandType.StoredProcedure;
returnReader = command.ExecuteReader();
//Connection.Close();
return returnReader;
}
}
private static SqlCommand BuildQueryCommand(SqlConnection connection,string storedProcName, IDataParameter[] parameters)
{
SqlCommand command = new SqlCommand( storedProcName, connection );
command.CommandType = CommandType.StoredProcedure;
foreach (SqlParameter parameter in parameters)
{
command.Parameters.Add( parameter );
}
return command;
}
public static DataSet RunProcedure(string storedProcName, IDataParameter[] parameters, string tableName )
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
DataSet dataSet = new DataSet();
connection.Open();
SqlDataAdapter sqlDA = new SqlDataAdapter();
sqlDA.SelectCommand = BuildQueryCommand(connection, storedProcName, parameters );
sqlDA.Fill( dataSet, tableName );
connection.Close();
return dataSet;
}
}
#endregion
}
}

[教程]CSS区别不同浏览器写法

mikel阅读(735)

区别不同浏览器,CSS hack写法:
区别IE6与FF:
#demo{
background:orange;
*background:blue;
}
区别IE6与IE7:
#demo{
background:green !important;
background:blue;
}
区别IE7与FF:
#demo{
background:orange;
*background:green;
}
区别FF,IE7,IE6:
#demo{
background:orange;
*background:green !important;
*background:blue;
}
注:IE都能识别*;标准浏览器(如FF)不能识别*;
IE6能识别*,但不能识别 !important,
IE7能识别*,也能识别!important;
FF不能识别*,但能识别!important;
我自己是使用下划线,我最开始区别 ie6 和 FF 的时候 习惯在代码里面加 /**/如: margin-top:1px;
margin-top/**/:5px;去实现我现在改变了写法
#demo{
background:orange;
_background:green !important;
_background:blue;
}
理由和上面说的一样,FF不认_ ie认_ ie6不认识!important 根据这些区别,采用不同的Hack 手法

[教程]将Flex与Spring框架集成

mikel阅读(791)

随着富Internet应用(RIA)技术的不断成熟,将类似于Adobe Flex这样的RIA应用与健壮的服务器端技术进行集成就变得越来越重要了。Java开发者最喜欢的服务器端框架之一Spring将在这个过程中扮演着重要的角色。

RIAvolutionize the Web的Marco Casario解释到他为何建议BlazeDS成为Spring与Flex结合的企业系统时说道:“Spring是一个开源框架,可以让开发人员开发起来 更加轻松。如果使用标准的JEE方式,你需要编写大量无用或者冗余的代码,还可能花费大量时间去实现J2EE的设计模式,而这些模式仅仅是为了应对技术上 的限制而不是真正的解决方案。Spring可以通过简化这些过程而节省大量时间。”

Christophe Coenraets解释了Flex与Spring集成的基本原理:

Spring的控制反转(Inversion of Control, 即IoC)的主要思想就是让容器实例化组件(并且注入其依赖)。但是在默认情况下,由Flex客户端远程访问的组件是在服务器端由Flex目的文件实例化 的。所以Flex与Spring集成的关键在于配置Flex目的文件以使其能够让Spring容器来管理实例化的Spring beans。Flex数据服务支持工厂的概念以便可以实例化这类客户化组件。工厂的作用仅仅在于向Flex目的文件提供准备好的组件实例,而不是让 Flex目的文件自己去实例化这些组件。

关于Flex与Spring、IBATISCairngorm的集成,Chris Giametta说道:

我相信可以创建一个一致的、模块化的、可重用的架构。这个架构既可以支持小型应用,也可以支持非常健壮 的企业级应用。项目成功的一个关键要素在于创建这样一个架构:新人能迅速投入进去,并且很快就能上手。我觉得将Flex与Spring、iBATIS和 Cairngorm集成可以帮助我迅速构建出一个基于模式的、可重用的架构。 

Sébastien Arbogast在不遗余力地发表一系列博文,以阐述如何构建全栈式Flex、BlazeDS和Spring集成解决方案。

Arbogast的这个全栈式集成,从下到上包括如下内容:JBoss作为应用服务器、MySQL作为数据存储、Hibernate完成数据访问、Spring用来构建业务层、BlazeDS作为远程服务、Flexe-genial用来构建富客户端。该系统使用Mavenflex-compiler-mojo插件进行构建。

Arbogast说:“这个项目的建立当然需要一些工作,但是——除去配置文件复制上的一些小问题外(而且这很快会得到改善)——它真的很干净,而且flex-compiler-mojo也非常棒。”

查看英文原文:Integrate Flex with Spring Framework

[资源]Reflector for .net framework 3.5下载

mikel阅读(725)

Reflector 应该是所有.Net 开发者必备的工具了, 这次重大的更新带来了很多方便和实用的特性:
1. C# 3.0/2.0 语言语法的完美反编译支持, 包括C# 3.0 的扩展方法, LINQ, Lambda, 以及C# 2.0的匿名方法等
2. "Code URL" 支持
3. 程序集浏览器的改进
4. 反编译浏览器的改进, 包括可以动态显示文档
5. 分析器的改进, 添加了“Exposed By”和“Instantiated By” 两种搜索
6. 搜索功能的改进, 包括字符串和常量搜索, 多关键字搜索
7. 资源查看器的改进
8. 更多的自定义选项和Windows Vista 的更好支持.
Reflector 下载地址:
http://www.aisto.com/roeder/dotnet/
Reflector 插件:
http://www.codeplex.com/reflectoraddins
Reflector 5.0 New Feature(PPT格式)
http://www.aisto.com/roeder/paper/reflector5.ppt
Enjoy Your Exploring Experience!~

[教程]理解Asp.Net Pages

mikel阅读(759)

1.动态编译

当一个ASP.NET Page被创建时,实际上创建的是一个.net类, 一个System.Web.UI.Page的实例. 页面的所有内容,包括HTML代码和Script代码,都被编译进这个.net类中.
当 有一个Request请求这个页面时,ASP.NET Framework检查被请求页面的相应的类是否存在,如果不存在则把页面编译成.net类,并且把编译了的类(assembly)存放到 Temporary Asp.Net Files这个目录中.这个文件夹一般位于
                          :\WINDOWS\Microsoft.NET\Framework\[version]\Temporary ASP.NET Files
当有新的请求到来时,编译过程将不在需要,先前编译好的类直接执行,并把结果返回给浏览器.

2.控件树

Asp.Net Page可以理解为是一个.Net类的源代码, 除此之外,也可以把Asp.Net Page理解为是一个控件包( a bag of controls).因为有点控件本身可能含有控件,因此更确切点一点,可以把Asp.Net Page理解为一个控件树.
例如:

 1<%@ Page Language="VB" Trace="true" %>
 2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 3 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 4<html xmlns="http://www.w3.org/1999/xhtml" >
 5<head id="Head1" runat="server">
 6    <title>Show Control Tree</title>
 7</head>
 8<body>
 9    <form id="form1" runat="server">
10    <div>
11
12    <asp:DropDownList
13        id="DropDownList1"
14        Runat="server">
15        <asp:ListItem Text="Oranges" />
16        <asp:ListItem Text="Apples" />
17    </asp:DropDownList>
18
19    <asp:Button
20        id="Button1"
21        Text="Submit"
22        Runat="server" />
23
24    </div>
25    </form>
26</body>
27</html>
28

这样一个Asp.Net Page, 它的控件树结构如下代码所示:

__Page ASP.showcontroltree_aspx
    ctl02 System.Web.UI.LiteralControl
    ctl00 System.Web.UI.HtmlControls.HtmlHead
        ctl01 System.Web.UI.HtmlControls.HtmlTitle
    ctl03 System.Web.UI.LiteralControl
    form1 System.Web.UI.HtmlControls.HtmlForm
        ctl04 System.Web.UI.LiteralControl
        DropDownList1 System.Web.UI.WebControls.DropDownList
        ctl05 System.Web.UI.LiteralControl
        Button1 System.Web.UI.WebControls.Button
        ctl06 System.Web.UI.LiteralControl
    ctl07

Asp.Net Page中包含的所有内容都被包含进一个.Net类中, 甚至包括HTML和纯文本内容.

3.Code-Behind Pages

Asp.Net Framework允许你创建两种类型的Asp.Net Pages, 单文件Pages和双文件Pages.这两种类型到底怎么样就不再赘述.稍微来看一下code-behind是如何工作的.
在Asp.Net 1.1中,Asp.Net Framework会为表现层页面(.aspx)和code-behind文件(.cs)产生两个单独的类,这两个类之间通过继承相关联,其中表现层页面类继承code-behind类.
由于继承是一个单向的关系,因此这种方法很脆弱.所有在表现层页面中声明的控件也必须同样在code-behind文件中声明,而且属性必须也相同.否则,控件触发的事件就可能不会被code-behind文件所捕获而加以处理.
在Asp.Net 2.0中,引入了一种新的机制:Partial Class.它允许把一个类的定义分散到不同的文件中.因此你就不需要在表现层页面和code-behind文件中同时声明,两者中任何的一个声明都可以在另一个中直接使用.

5.处理页面事件

当你请求一个页面时,页面触发事件的顺序如下:

  1. PreInit

  2. Init

  3. InitComplete

  4. PreLoad

  5. Load

  6. LoadComplete

  7. PreRender

  8. PreRenderComplete

  9. SaveStateComplete

  10. Unload

[教程]ASP.Net MVC入门教程

mikel阅读(763)

Introduction

MVC应该算是一个古老的Design Pattern了,无论是在win form程序还是web程序中,它的应用都是比较广泛的。MVC也是我在学校中学习到的第一个设计模式。终于,可以在ASP.NET中应用了。本文的例子 所用的是ASP.NET MVC Preview 2,可以在这里下载

Create a new MVC project

菜单File->New Project ->ASP.NET Web MVC Application
2.jpg
新创建的项目是一个完整的可以运行的Sample程序。
新创建的MVC Project和传统的Asp.net web application不同,MVC Project包含有如下四个文件夹:

  1. Content Folder : 这个文件夹中放一些支持文件,如CSS等。
  2. Controller Folder :这个文件夹中放所以的Controller文件
  3. Models folder : 这个文件夹存放所有的data model文件,包括:LINQ to SQL DBML文件,Entity文件
  4. Views folder : 存放所有的页面文件,包括master文件。Master等需要被共享访问的需要被放在一个Shared子文件夹中。

Advantages of an MVC-Based Web Application

  1. 把程序分为Model, View和Controller之后,更容易控制程序的复杂性
  2. 没有了传统的Asp.Net中的viewstate和server端的form,使得开发人员可以实现对页面的完全控制。当然也失去了viewstate和server端form带来的各种好处
  3. 支持测试驱动开发

Features of the ASP.NET MVC Framework

  1. 应用程序的业务分离,支持测试驱动开发
  2. 可扩展和支持插件的Framework。开发人员都可以根据自己的需要修改甚至替换ASP.NET MVC Framework的各个component,也可以以插件的形式开发自己的View Engine,URL Routing Policy等各种component。Asp.Net MVC Framework甚至支持依赖注入(Dependency Injection)和控制反转(Inversion of Control)等容器模式。
  3. 强大的URL-Mapping功能。使得URL地址更有意义(REST)。URL中不再包括文件扩展名。
  4. 对很多传统Asp.Net特性的支持。如<%=%>, user control等。

     

The MVC Framework and Postbacks

Asp.Net MVC 不再使用传统的Asp.Net Web Application的postback模式。取而代之的是,所有的客户端发回服务器端的request都会被映射到某一个controller类中, 这使UI logic和business logic得以分离,从而有助于提高程序的可测试性。

Understanding the MVC Project Execution Process

Request被发回服务器端之后,首先都由UrlRoutingModule对象来解析这个Request,并根据URL找到一个匹配的Router对象,之后由这个Router对象来处理这个Request。 MVC Application的处理流程:

  1. Initial Request: routers在Global.ascx中被添加到RouteTable中。
  2. Routing: UrlRoutingModule找到匹配的Router对象,决定使用哪个controller,调用哪个action。
  3. Map to controller: MvcRouteHandler会尝试通过routedata来创建controller的type name.
  4. Create Controller
  5. Execute Controller

[代码]Object/DataSet Relational Mapping(对象/数据集关系映射)补

mikel阅读(686)

  1using System;
  2using System.Data;
  3using System.Configuration;
  4using System.Collections;
  5using System.Web;
  6using System.Web.Security;
  7using System.Web.UI;
  8using System.Web.UI.WebControls;
  9using System.Web.UI.WebControls.WebParts;
 10using System.Web.UI.HtmlControls;
 11
 12using IBatisNet.DataMapper;
 13using System.Reflection;
 14
 15/// <summary>
 16/// ODRM为结合ORM与DataSet,并自动根据O和DataSet生成对象,以便业务层处理
 17/// </summary>

 18public partial class ODRM_test : PageBase
 19{
 20    protected void Page_Load(object sender, EventArgs e)
 21    {
 22        if (!IsPostBack)
 23        {
 24            DataSet set11 = Mapper.Instance().QueryForDataSet("SelectXTM_UserByKey_Test",UIhashtable);
 25            DataTable table1 = ConvertDataTable(set11, "");
 26            //这里为自己定义的序列化类
 27            cXTM_User[] objModel = new cXTM_User[table1.Rows.Count];
 28            //DataTable转化为序列化类数组
 29            for (int y = 0; y < table1.Rows.Count; y++)
 30            {
 31                objModel[y] = new cXTM_User();
 32                DataTableConvertObject(table1.Rows[y], objModel[y]); 
 33            }

 34            //以DataSet模式绑定
 35            ExDataGrid1.DataSource = table1;
 36            //以序列化对象模式绑定
 37            //ExDataGrid1.DataSource = objModel;
 38            ExDataGrid1.DataBind();
 39        }

 40    }

 41
 42    protected void ExDataGrid1_ItemDataBound(object sender, DataGridItemEventArgs e)
 43    {
 44        /*
 45         * 该部分应用范围
 46         * 查询一条数据的修改,可以用objModel.UserName
 47         * 而不必再使用DataTable[0].Rows[0]["UserName"]的模式
 48         * 提高面向对象的程度,并减少业务流程部分编码
 49         */

 50
 51        if (e.Item.ItemIndex != 1)
 52        {
 53            cXTM_User objModel = new cXTM_User();
 54            
 55            //如果为DataSet填充的DataGrid
 56            if (e.Item.DataItem.GetType().FullName == "System.Data.DataRowView")
 57            {
 58                DataTableConvertObject((DataRow)((DataRowView)e.Item.DataItem).Row, objModel);      
 59            }

 60            //否则认为为序列化对象填充
 61            else 
 62            {
 63                objModel = (cXTM_User)e.Item.DataItem; 
 64                   
 65            }

 66        }

 67    }

 68
 69    #region 指定对象函数
 70    /// <summary>
 71    /// 数据集中一行DataRow转换为指定对象,并填充数据
 72    /// </summary>
 73    /// <param name="row">数据集中一行</param>
 74    /// <param name="objModel">指定对象</param>

 75    private void DataTableConvertObject(DataRow row, cXTM_User objModel)
 76    {
 77        Hashtable hTable = new Hashtable();
 78        hTable = DataRowConvertHashtable(row);
 79        Type entitytype = Type.GetType(objModel.GetType().AssemblyQualifiedName);
 80
 81        for (int j = 0; j < objModel.Propertylist.Length; j++)
 82        {
 83            PropertyInfo propertyinfo = entitytype.GetProperty(objModel.Propertylist[j]);
 84            propertyinfo.SetValue(objModel, hTable[objModel.Propertylist[j]], null);
 85        }

 86    }

 87
 88    /// <summary>
 89    /// 对象转换为哈希表
 90    /// </summary>
 91    /// <param name="objModel">有数据的对象</param>
 92    /// <returns>填充数据后的哈希表</returns>

 93    public Hashtable ObjectConvertHashtable(cXTM_User objModel)
 94    {
 95        Hashtable hTable = new Hashtable();
 96        Type entitytype = Type.GetType(objModel.GetType().AssemblyQualifiedName);
 97        for (int j = 0; j < objModel.Propertylist.Length; j++)
 98        {
 99            PropertyInfo propertyinfo = entitytype.GetProperty(objModel.Propertylist[j]);
100            hTable.Add(objModel.Propertylist[j], propertyinfo.GetValue(objModel, null));
101        }

102        return hTable;
103    }

104
105    /// <summary>
106    /// 对象转换为DataTable,并有单行DataRow
107    /// </summary>
108    /// <param name="objModel">有数据的对象</param>
109    /// <returns></returns>

110    public DataTable ObjectConvertDataTableWidthRow(cXTM_User objModel)
111    {
112        return ObjectConvertDataTableWidthRow(objModel, "");
113    }

114
115    /// <summary>
116    /// 对象转换为DataTable,并有单行DataRow
117    /// </summary>
118    /// <param name="objModel">有数据的对象</param>
119    /// <returns></returns>

120    public DataTable ObjectConvertDataTableWidthRow(cXTM_User objModel, string DataMapper)
121    {
122        Type entitytype = Type.GetType(objModel.GetType().AssemblyQualifiedName);
123        DataTable dt = new DataTable();
124        if (DataMapper != "")
125        {
126            dt = new DataTable(DataMapper);
127        }

128        dt.Columns.Clear();
129        for (int j = 0; j < objModel.Propertylist.Length; j++)
130        {
131            PropertyInfo propertyinfo = entitytype.GetProperty(objModel.Propertylist[j]);
132            dt.Columns.Add(new DataColumn(objModel.Propertylist[j], propertyinfo.GetType()));
133        }

134        DataRow row = dt.NewRow();
135        for (int j = 0; j < objModel.Propertylist.Length; j++)
136        {
137            PropertyInfo propertyinfo = entitytype.GetProperty(objModel.Propertylist[j]);
138            row[objModel.Propertylist[j]] = propertyinfo.GetValue(objModel, null);
139        }

140        dt.Rows.Add(row);
141
142        return dt;
143    }

144
145    /// <summary>
146    /// 对象转换为DataTable,并有多行DataRow
147    /// </summary>
148    /// <param name="objModel">有数据的对象</param>
149    /// <returns></returns>

150    public DataTable ObjectConvertDataTableWidthRows(cXTM_User[] objModel)
151    {
152        return ObjectConvertDataTableWidthRows(objModel, "");
153    }

154
155    /// <summary>
156    /// 对象转换为DataTable,并有多行DataRow
157    /// </summary>
158    /// <param name="objModel">有数据的对象</param>
159    /// <returns></returns>

160    public DataTable ObjectConvertDataTableWidthRows(cXTM_User[] objModel, string DataMapper)
161    {
162        Type entitytype = Type.GetType(objModel.GetType().AssemblyQualifiedName);
163        DataTable dt = new DataTable();
164        if (DataMapper != "")
165        {
166            dt = new DataTable(DataMapper);
167        }

168        if (objModel.Length == 0)
169        {
170            return dt;
171        }

172        dt.Columns.Clear();
173        for (int j = 0; j < objModel[0].Propertylist.Length; j++)
174        {
175            PropertyInfo propertyinfo = entitytype.GetProperty(objModel[0].Propertylist[j]);
176            dt.Columns.Add(new DataColumn(objModel[0].Propertylist[j], propertyinfo.GetType()));
177        }

178
179        for (int i = 0; i < objModel.Length; i++)
180        {
181            DataRow row = dt.NewRow();
182            for (int j = 0; j < objModel[i].Propertylist.Length; j++)
183            {
184                PropertyInfo propertyinfo = entitytype.GetProperty(objModel[i].Propertylist[j]);
185                row[objModel[i].Propertylist[j]] = propertyinfo.GetValue(objModel[i], null);
186            }

187            dt.Rows.Add(row);
188        }

189        return dt;
190    }

191    #endregion

192
193    #region 通用函数
194
195    /// <summary>
196    /// 转换为DataTable
197    /// </summary>
198    /// <param name="Source">数据源</param>
199    /// <param name="DataMember">数据表名称</param>

200    public static DataTable ConvertDataTable(object Source, string DataMember)
201    {
202        DataTable baseTable = new DataTable();
203        if (Source is DataTable)
204        {
205            baseTable = (DataTable)Source;
206            return baseTable;
207        }

208        if (Source is DataSet)
209        {
210
211            DataSet set1 = (DataSet)Source;
212            if ((set1.Tables.Count > 1&& ((DataMember == null|| (DataMember == "")))
213            {
214                throw new Exception("If there is more than one table in your dataset, you must define the DataMember property to specify which table to use.");
215            }

216            if (set1.Tables.Count < 1)
217            {
218                throw new Exception("There are no tables in the datasource.");
219            }

220            if ((DataMember != null&& (DataMember != ""))
221            {
222                baseTable = set1.Tables[DataMember];
223                return baseTable;
224            }

225            else
226            {
227                baseTable = set1.Tables[0];
228                return baseTable;
229            }

230
231        }

232        return baseTable;
233    }

234
235    /// <summary>
236    /// 返回DataTable为哈希表键值对
237    /// </summary>
238    /// <param name="SourceTable">数据行对象</param>
239    /// <returns>填充后哈希表</returns>

240    public static Hashtable DataRowConvertHashtable(DataRow SourceRow)
241    {
242        Hashtable hTable = new Hashtable();
243        IList list = SourceRow.ItemArray;
244        object[] tObj = new object[SourceRow.Table.Columns.Count];
245
246        for (int i = 0; i < SourceRow.Table.Columns.Count; i++)
247        {
248            tObj[SourceRow.Table.Columns.IndexOf(SourceRow.Table.Columns[i].ColumnName)] = SourceRow.Table.Columns[i].ColumnName;
249        }

250
251        for (int x = 0; x < list.Count; x++)
252        {
253            hTable.Add(tObj[x].ToString(), list[x]);
254        }

255        return hTable;
256    }

257
258    #endregion

259
260
261
262
263}

264