原文链接:http://www.javaeye.com/blog/52178
说明:可以参看原链接的评论
===================================================
1, LVS做前端四层均衡负载
基于IP虚拟分发的规则,不同于apache,squid这些7层基于http协议的反向代理软件, LVS在性能上往往能得到更好的保证!
2,squid 做前端反向代理加缓存
squid 是业内公认的优秀代理服务器,其缓存能力更让许多高负载网站青睐!(比如新浪,网易等)
使用他, 配合ESI做WEB动态内容及图片缓存,最合适不过了
3,apache 用来处理php或静态html,图片
apache是业内主流http服务器,稳定性与性能都能得到良好保证!
4,JBOSS 用来处理含复杂的业务逻辑的请求
JBOSS是red hat旗下的优秀中间件产品,在java开源领域小有名气,并且完全支持j2ee规范的,功能非常强大
使用他,既能保证业务流程的规范性,又可以节省开支(免费的)
5,mySQL数据库
使用mySQL数据库,达到百万级别的数据存储,及快速响应,应该是没问题的
6,memcache作为分布式缓存
缓存应用数据,或通过squid解析esi后,作为数据载体
[教程]Linq to SQL 查询
原贴
简单地说,LINQ 是支持以类型安全方式查询数据的一系列语言扩展;它将在代号为“Orcas”的下一个版本 Visual Studio 中发布。待查询数据的形式可以是 XML(LINQ 到 XML)、数据库(启用 LINQ 的 ADO.NET,其中包括 LINQ 到 SQL、LINQ 到 Dataset 和 LINQ 到 Entities)和对象 (LINQ 到 Objects) 等。LINQ 体系结构如图 1 所示。

让我们看一些代码。在即将发布的“Orcas”版 C# 中,LINQ 查询可能如下所示:
var overdrawnQuery = from account in db.Accounts
where account.Balance < 0
select new { account.Name, account.Address };
当使用 foreach 遍历此查询的结果时,返回的每个元素都将包含一个余额小于 0 的帐户的名称和地址。
从 以上示例中立即可以看出该语法类似于 SQL。几年前,Anders Hejlsberg(C# 的首席设计师)和 Peter Golde 曾考虑扩展 C# 以更好地集成数据查询。Peter 时任 C# 编译器开发主管,当时正在研究扩展 C# 编译器的可能性,特别是支持可验证 SQL 之类特定于域的语言语法的加载项。另一方面,Anders 则在设想更深入、更特定级别的集成。他当时正在构思一组“序列运算符”,能在实现 IEnumerable 的任何集合以及实现 IQueryable 的远程类型查询上运行。最终,序列运算符的构思获得了大多数支持,并且 Anders 于 2004 年初向比尔·盖茨的 Thinkweek 递交了一份关于本构思的文件。反馈对此给予了充分肯定。在设计初期,简单查询的语法如下所示:
sequence<Customer> locals = customers.where(ZipCode == 98112);
在 此例中,Sequence 是 IEnumerable<T> 的别名;“where”一词是编译器能理解的一种特殊运算符。Where 运算符的实现是一种接受 predicate 委托(即 bool Pred<T>(T item) 形式的委托)的普通 C# 静态方法。本构思的目的是让编辑器具备与运算符有关的特殊知识。这样将允许编译器正确调用静态方法并创建代码,将委托与表达式联系起来。
假设上述示例是 C# 的理想查询语法。在没有任何语言扩展的情况下,该查询在 C# 2.0 中又会是什么样子?
IEnumerable<Customer> locals = EnumerableExtensions.Where(customers,
delegate(Customer c)
{
return c.ZipCode == 98112;
});
这 个代码惊人地冗长,而且更糟糕的是,需要非常仔细地研究才能找到相关的筛选器 (ZipCode == 98112)。这只是一个简单的例子;试想一下,如果使用数个筛选器、投影等,要读懂代码该有多难。冗长的根源在于匿名方法所要求的语法。在理想的查询 中,除了要计算的表达式,表达式不会提出任何要求。随后,编译器将尝试推断上下文;例如,ZipCode 实际上引用了 Customer 上定义的 ZipCode。如何解决这一问题?将特定运算符的知识硬编码到语言中并不能令语言设计团队满意,因此他们开始为匿名方法寻求替代语法。他们要求该语法应 极其简练,但又不必比匿名方法当前所需的编译器要求更多的知识。最终,他们发明了 lambda 表达式。
Lambda 表达式
Lambda 表 达式是一种语言功能,在许多方面类似于匿名方法。事实上,如果 lambda 表达式首先被引入语言,那么就不会有对匿名方法的需要了。这里的基本概念是可以将代码视为数据。在 C# 1.0 中,通常可以将字符串、整数、引用类型等传递给方法,以便方法对那些值进行操作。匿名方法和 lambda 表达式扩展了值的范围,以包含代码块。此概念常见于函数式编程中。
我们再借用以上示例,并用 lambda 表达式替换匿名方法:
IEnumerable<Customer> locals =
EnumerableExtensions.Where(customers, c => c.ZipCode == 91822);
有 几个需要注意的地方。对于初学者而言, lambda 表达式简明扼要的原因有很多。首先,没有使用委托关键字来引入构造。取而代之的是一个新的运算符 =>,通知编译器这不是正则表达式。其次,Customer 类型是从使用中推断出来的。在此例中,Where 方法的签名如下所示:
public static IEnumerable<T> Where<T>(
IEnumerable<T> items, Func<T, bool> predicate)
编 译器能够推断“c”是指客户,因为 Where 方法的第一个参数是 IEnumerable<Customer>,因此 T 事实上必须是 Customer。利用这种知识,编译器还可验证 Customer 具有一个 ZipCode 成员。最后,没有指定的返回关键字。在语法形式中,返回成员被省略,但这只是为了语法便利。表达式的结果仍将视为返回值。
与匿名方法一样,Lambda 表达式也支持变量捕获。例如,对于在 lambda 表达式主体内包含 lambda 表达式的方法,可以引用其参数或局部变量:
public IEnumerable<Customer> LocalCusts(
IEnumerable<Customer> customers, int zipCode)
{
return EnumerableExtensions.Where(customers,
c => c.ZipCode == zipCode);
}
最后,Lambda 表达式支持更冗长的语法,允许您显式指定类型,以及执行多条语句。例如:
return EnumerableExtensions.Where(customers,
(Customer c) => { int zip = zipCode; return c.ZipCode == zip; });
好消息是,我们向原始文章中提议的理想语法迈进了一大步,并且我们能够利用一个通常能在查询运算符以外发挥作用的语言功能来实现这一目标。让我们再次看一下我们目前所处的阶段:
IEnumerable<Customer> locals =
EnumerableExtensions.Where(customers, c => c.ZipCode == 91822);
这里存在一个明显的问题。客户目前必须了解此 EnumerableExtensions 类,而不是考虑可在 Customer 上执行的操作。另外,在多个运算符的情况下,使用者必须逆转其思维以编写正确的语法。例如:
IEnumerable<string> locals =
EnumerableExtensions.Select(
EnumerableExtensions.Where(customers, c => c.ZipCode == 91822),
c => c.Name);
请注意,Select 属于外部方法,尽管它是在 Where 方法结果的基础上运行的。理想的语法应该更类似以下代码:
sequence<Customer> locals =
customers.where(ZipCode == 98112).select(Name);
因此,是否可利用另一种语言功能来进一步接近实现理想语法呢?
扩展方法
结 果证明,更好的语法将以被称为扩展方法的语言功能形式出现。扩展方法基本上属于可通过实例语法调用的静态方法。上述查询问题的根源是我们试图向 IEnumerable<T> 添加方法。但如果我们要添加运算符,如 Where、Select 等,则所有现有和未来的实现器都必须实现那些方法。尽管那些实现绝大多数都是相同的。在 C# 中共享“接口实现”的唯一方法是使用静态方法,这是我们处理以前使用的 EnumerableExtensions 类的一个成功方法。
假设我们转而将 Where 方法编写为扩展方法。那么,查询可重新编写为:
IEnumerable<Customer> locals =
customers.Where(c => c.ZipCode == 91822);
对于此简单查询,该语法近乎完美。但将 Where 方法编写为扩展方法的真正含义是什么呢?其实非常简单。基本上,因为静态方法的签名发生更改,因此“this”修饰符就被添加到第一个参数:
public static IEnumerable<T> Where<T>(
this IEnumerable<T> items, Func<T, bool> predicate)
此 外,必须在静态类中声明该方法。静态类是一种只能包含静态成员,并在类声明中用静态修饰符表示的类。这就它的全部含义。此声明指示编译器允许在任何实现 IEnumerable<T> 的类型上用与实例方法相同的语法调用 Where。但是,必须能够从当前作用域访问 Where 方法。当包含类型处于作用域内时,方法也在作用域内。因此,可以通过 Using 指令将扩展方法引入作用域。(有关详细信息,请参见侧栏上的“扩展方法”。)
显然,扩展 方法有助于简化我们的查询示例,但除此之外,这些方法是不是一种广泛有用的语言功能呢?事实证明扩展方法有多种用途。其中一个最常见的用途可能是提供共享接口实现。例如,假设您有以下接口:
interface IDog
{
// Barks for 2 seconds
void Bark();
void Bark(int seconds);
}
此接口要求每个实现器都应编写适用于两种重载的实现。有了“Orcas”版 C#,接口变得很简单:
interface IDog
{
void Bark(int seconds);
}
扩展方法可添加到另一个类:
static class DogExtensions
{
// Barks for 2 seconds
public static void Bark(this IDog dog)
{
dog.Bark(2);
}
}
接口实现器现在只需实现单一方法,但接口客户端却可以自由调用任一重载。
我们现在拥有了用于编写筛选子句的非常接近理想的语法,但“Orcas”版 C# 仅限于此吗?并不全然。让我们对示例稍作扩展,相对于整个客户对象,我们只投影出客户名称。如我前面所述,理想的语法应采用如下形式:
sequence<string> locals =
customers.where(ZipCode == 98112).select(Name);
仅用我们讨论过的语言扩展,即 lambda 表达式和扩展方法,此代码可重新编写为如下所示:
IEnumerable<string> locals =
customers.Where(c => c.ZipCode == 91822).Select(c => c.Name);
请注意,此查询的返回类型不同,它是 IEnumerable<string> 而不是 IEnumerable<Customer>。这是因为我们仅从 select 语句中返回客户名称。
当投影只是单一字段时,该方法确实很有效。但是,假设我们不仅要返回客户的名称,还要返回客户的地址。理想的语法则应如下所示:
locals = customers.where(ZipCode == 98112).select(Name, Address);
匿名类型
如果我们想继续使用我们现有的语法来返回名称和地址,我们很快便会面临问题,即不存在仅包含 Name 和 Address 的类型。虽然我们仍然可以编写此查询,但是必须引入该类型:
class CustomerTuple
{
public string Name;
public string Address;
public CustomerTuple(string name, string address)
{
this.Name = name;
this.Address = address;
}
}
然后我们才能使用该类型,即此处的 CustomerTuple,以生成我们查询的结果。
IEnumerable<CustomerTuple> locals =
customers.Where(c => c.ZipCode == 91822)
.Select(c => new CustomerTuple(c.Name, c.Address));
那 确实像许多用于投影出字段子集的样板代码。而且还往往不清楚如何命名此种类型。CustomerTuple 确实是个好名称吗?如果投影出 Name 和 Age 又该如何命名?那也可以叫做 CustomerTuple。因此,问题在于我们拥有样板代码,而且似乎无法为我们创建的类型找到任何恰当的名称。此外,还可能需要许多不同的类型,如何 管理这些类型很快便可能成为一个棘手的问题。
这正是匿名类型要解决的问题。此功能主要允许在无需指定名称的情况下创建结构化类型。如果我们使用匿名类型重新编写上述查询,其代码如下所示:
locals = customers.Where(c => c.ZipCode == 91822)
.Select(c => new { c.Name, c.Address });
此代码会隐式创建一个具有 Name 和 Address 字段的类型:
class
{
public string Name;
public string Address;
}
此类型不能通过名称引用,因为它没有名称。创建匿名类型时,可显式声明字段的名称。例如,如果正在创建的字段派生于一条复杂的表达式,或纯粹不需要名称,就可以更改名称:
locals = customers.Where(c => c.ZipCode == 91822)
.Select(c => new { FullName = c.FirstName + “ “ + c.LastName,
HomeAddress = c.Address });
在此情形下,生成的类型具有名为 FullName 和 HomeAddress 的字段。
这样我们又向理想世界前进了一步,但仍存在一个问题。您将发现,我在任何使用匿名类型的地方都策略性地省略了局部变量的类型。显然我们不能声明匿名类型的名称,那我们如何使用它们?
隐式类型化部变量
还有另一种语言功能被称为隐式类型化局部变量(或简称为 var),它负责指示编译器推断局部变量的类型。例如:
var integer = 1;
在此例中,整数具有 int 类型。请务必明白,这仍然是强类型。在动态语言中,整数的类型可在以后更改。为说明这一点,以下代码不会成功编译:
var integer = 1;
integer = “hello”;
C# 编译器将报告第二行的错误,表明无法将字符串隐式转换为 int。
在上述查询示例中,我们现在可以编写完整的赋值,如下所示:
var locals =
customers
.Where(c => c.ZipCode == 91822)
.Select(c => new { FullName = c.FirstName + “ “ + c.LastName,
HomeAddress = c.Address });
局部变量的类型最终成为 IEnumerable<?>,其中“?”是无法编写的类型的名称(因为它是匿名的)。
隐式类型化局部变量只是:方法内部的局部变量。它们无法超出方法、属性、索引器或其他块的边界,因为该类型无法显式声明,而且“var”对于字段或参数类型而言是非法的。
事实证明,隐式类型化局部变量在查询的环境之外非常便利。例如,它有助于简化复杂的通用实例化:
var customerListLookup = new Dictionary<string, List<Customer>>();
现在我们的查询取得了良好进展;我们已经接近理想的语法,而且我们是用通用语言功能来达成的。
有趣的是,我们发现,随着越来越多的人使用过此语法,经常会出现允许投影超越方法边界的需求。如我们以前所看到的,这是可能的,只要从 Select 内部调用对象的构造函数来构建对象即可。但是,如果没有用来准确接受您需要设置的值的构造函数,会发生什么呢?
对象初始值
为解决这一问题,即将发布的“Orcas”版本提供了一种被称为对象初始值的 C# 语言功能。对象初始值主要允许在单一表达式中为多个属性或字段赋值。例如,创建对象的常见模式是:
Customer customer = new Customer();
customer.Name = “Roger”;
customer.Address = “1 Wilco Way”;
此时,Customer 没有可以接受名称和地址的构造函数;但是存在两个属性,即 Name 和 Address,当创建实例后即可设置它们。对象初始值允许使用以下语法创建相同的结果:
Customer customer = new Customer()
{ Name = “Roger”, Address = “1 Wilco Way” };
在我们前面的 CustomerTuple 示例中,我们通过调用其构造函数创建了 CustomerTuple 类。我们也可以通过对象初始值获得同样的结果:
var locals =
customers
.Where(c => c.ZipCode == 91822)
.Select(c =>
new CustomerTuple { Name = c.Name, Address = c.Address });
请注意,对象初始值允许省略构造函数的括号。此外,字段和可设置的属性均可在对象初始值的主体内部进行赋值。
我们现在已经拥有在 C# 中创建查询的简洁语法。尽管如此,我们还有一种可扩展途径,可通过扩展方法以及一组本身非常有用的语言功能来添加新的运算符(Distinct、OrderBy、Sum 等)。
语 言设计团队现在有了数种可赖以获得反馈的原型。因此,我们与许多富于 C# 和 SQL 经验的参与者组织了一项可用性研究。几乎所有反馈都是肯定的,但明显疏忽了某些东西。具体而言,开发人员难以应用他们的 SQL 知识,因为我们认为理想的语法与他们擅长领域的专门技术并不很符合。
查询表达式
于是,语言设计团队设计了一种与 SQL 更为相近的语法,称为查询表达式。例如,针对我们的示例的查询表达式可如下所示:
var locals = from c in customers
where c.ZipCode == 91822
select new { FullName = c.FirstName + “ “ +
c.LastName, HomeAddress = c.Address };
查询表达式是基于上述语言功能构建而成。它们在语法上,完全转换为我们已经看到的基础语法。例如,上述查询可直接转换为:
var locals =
customers
.Where(c => c.ZipCode == 91822)
.Select(c => new { FullName = c.FirstName + “ “ + c.LastName,
HomeAddress = c.Address });
查 询表达式支持许多不同的“子句”,如 from、where、select、orderby、group by、let 和 join。这些子句先转换为对等的运算符调用,后者进而通过扩展方法实现。如果查询语法不支持必要运算符的子句,则查询子句和实现运算符的扩展方法之间的 紧密关系很便于将两者结合。例如:
var locals = (from c in customers
where c.ZipCode == 91822
select new { FullName = c.FirstName + “ “ +
c.LastName, HomeAddress = c.Address})
.Count();
在本例中,查询现在返回在 91822 ZIP Code 区居住的客户人数。
通 过该种方法,我们已经设法在结束时达到了开始时的目标(我对这一点始终觉得非常满意)。下一版本的 C# 的语法历经数年时间的发展,尝试了许多新的语言功能,才最终到达近乎于 2004 年冬提议的原始语法的境界。查询表达式的加入以 C# 即将发布的版本的其他语言功能为基础,并促使许多查询情况更便于具有 SQL 背景的开发人员阅读和理解。
[资源]ASP.net MVC Framework Preview3发布
[文档]SQL Server 2000 系统表和 SQL Server 2005 系统视图之间的映射
本主题说明了 SQL Server 2000 系统表和 SQL Server 2005 系统视图之间的映射。
下表将 SQL Server 2000 中 master 数据库内的系统表映射到它们在 SQL Server 2005 中对应的一个或多个系统视图。
| 系统表 | 系统视图 | 视图类型 |
|---|---|---|
|
sysaltfiles |
目录视图 |
|
|
syscacheobjects |
动态管理视图 |
|
|
syscharsets |
兼容性视图 |
|
|
sysconfigures |
目录视图 |
|
|
syscurconfigs |
目录视图 |
|
|
sysdatabases |
目录视图 |
|
|
sysdevices |
目录视图 |
|
|
syslanguages |
兼容性视图 |
|
|
syslockinfo |
动态管理视图 |
|
|
syslocks |
动态管理视图 |
|
|
syslogins |
目录视图 |
|
|
sysmessages |
目录视图 |
|
|
sysoledbusers |
目录视图 |
|
|
sysopentapes |
动态管理视图 |
|
|
sysperfinfo |
动态管理视图 |
|
|
sysprocesses |
动态管理视图 |
|
|
sysremotelogins |
目录视图 |
|
|
sysservers |
目录视图 |
下表将 SQL Server 2000 中每个数据库内的系统表映射到它们在 SQL Server 2005 中对应的一个或多个系统视图。
| 系统表 | 系统视图 | 视图类型 |
|---|---|---|
|
syscolumns |
目录视图 |
|
|
syscomments |
目录视图 |
|
|
sysconstraints |
目录视图 |
|
|
sysdepends |
目录视图 |
|
|
sysfilegroups |
目录视图 |
|
|
sysfiles |
目录视图 |
|
|
sysforeignkeys |
目录视图 |
|
|
sysindexes |
目录视图 |
|
|
sysindexkeys |
目录视图 |
|
|
sysmembers |
目录视图 |
|
|
sysobjects |
目录视图 |
|
|
syspermissions |
目录视图 |
|
|
sysprotects |
目录视图 |
|
|
sysreferences |
目录视图 |
|
|
systypes |
目录视图 |
|
|
sysusers |
目录视图 |
|
|
sysfulltextcatalogs |
目录视图 |
[代码]SQLServer2005读取表信息
declare @schemaName varchar(100)
declare @tblName varchar(100)
declare @colName varchar(100)
declare @objectID int
set @schemaName = 'College'
set @tblName = 'Student'
set @colName = 'iStatusID'
set @objectID = OBJECT_ID(@schemaName + '.' + @tblName)
— 1. How to check the Column is nullable?
Select COLUMNPROPERTY(@objectID,@colName,'AllowsNull') AS 'Allows Null?';
— 2. How to check the Column is an identity?
Select COLUMNPROPERTY(@objectID,@colName,'IsIdentity') AS 'Identity?';
— 3. How to check the Column is an FullTextEnabled?
Select COLUMNPROPERTY(@objectID,@colName,'IsFulltextIndexed') AS 'FullTextEnabled?';
— 4. How to check the Column's datatype?
select b.name as 'Datatype', a.max_length, a.precision, a.scale
from sys.columns a
join sys.types b on a.system_type_id = b.system_type_id and a.user_type_id = b.user_type_id
where OBJECT_NAME(a.object_id) = @tblName and a.name = @colName
— 5. How to identify that the default constraints have been created for the Column?
select a.name as 'Default Constraint Name'
from sys.default_constraints a
join sys.all_columns b on a.parent_object_id = b.object_id and a.parent_column_id = b.column_id
where object_name(parent_object_id) = @tblName and b.name = @colName
— 6. How to identify that the foreignkey constraints for the table?
select name as 'ForeignKeyConstraint Name' from sys.objects
where type = 'F' and parent_object_id = @objectID
— 7. Select all Constraints associated with this table and Column.
Select Constraint_Name from INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE
Where Table_Name = @tblName and Column_Name = @colName
— 8. Find all the Objects from sys.objects table by specifying the “type”.
select name from sys.objects Where parent_object_id = @objectID and type = 'D'
[教程]SQL Server 2005:向系统表说再见
微软的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系统表结构
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 = 静态(该设置在服务器重新启动时生效)。 |
syscurconfigs 页首
每个当前配置选项各占一项。另外,该表还包含四个描述配置结构的项。 syscurconfigs 在由用户查询时动态生成。有关更多信息,请参见 sysconfigures。
| 列名 | 数据类型 | 描述 |
|---|---|---|
| value | int | 用户可修改的变量值(仅在已执行 RECONFIGURE 的情况下由 Microsoft? SQL Server? 使用)。 |
| config | smallint | 配置变量号。 |
| comment | nvarchar(255) | 对配置选项的解释。 |
| status | smallint | 表示选项状态的位图。可能的值包括:
0 = 静态(该设置在服务器重新启动时生效)。 |
sysdatabases 页首
Microsoft? SQL Server? 上的每个数据库在表中占一行。最初安装 SQL Server 时, sysdatabases 包含 master 、 model 、 msdb 、 mssqlweb 和 tempdb 数据库的项。该表只存储在 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 设置。 可以同时打开多个位。 |
| 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 = 已发布。 |
| 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 = 列允许空值。 |
| type | tinyint | systypes 中的物理存储类型。 |
| usertype | smallint | systypes 中的用户定义数据类型 ID。 |
| printfmt | varchar(255) | 仅限内部使用。 |
| prec | smallint | 该列的精度级别。 |
| scale | int | 该列的小数位数。 |
| iscomputed | int | 表示是否已计算该列的标志:
0 = 未计算。 |
| isoutparam | int | 表示该过程参数是否是输出参数:
1 = 真。 |
| isnullable | int | 表示该列是否允许空值:
1 = 真。 |
sysconstraints 页首
包含约束映射,映射到拥有该约束的对象。该系统目录存储在每个数据库中。
| 列名 | 数据类型 | 描述 |
|---|---|---|
| constid | int | 约束号。 |
| id | int | 拥有该约束的表 ID。 |
| colid | smallint | 在其上定义约束的列 ID,如果是表约束则为 0。 |
| spare1 | tinyint | 保留。 |
| status | int | 位图指示状态。可能的值包括:
1 = PRIMARY KEY 约束。 |
| 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 = 默认设备。 |
| 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 = 聚集索引 |
| 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 是分配给 text 或 image 数据的页计数。否则是分配给索引的页计数。 |
| used | int | 如果 indid = 0 或 indid = 1, used 是用于所有索引和表数据的总页数。如果 indid = 255, used 是用于 text 或 image 数据的页计数。否则是用于索引的页计数。 |
| 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 约束 |
| 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 约束 |
| 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架构
Bob Beauchemin
DevelopMentor
适用于:
Microsoft ADO.NET 2.0
Microsoft Visual Studio 2005
C# 编程语言
摘要:了解在 ADO.NET 中对于从您的数据源访问元数据的增强支持。
下载相关的 SchemasSample.exe 示例代码。
本页内容
深入了解新的公共元数据 API
究竟谁需要元数据?
我能得到什么样的元数据?
Restrictions
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 来公开元数据时有四个障碍需要考虑。
-
元数据集合和信息在数据库间是有差别的。例如,SQL Server 用户可能想要公开一个链接服务器的集合,但是 oracle 用户可能对关于 oracle 序列的信息感兴趣。
-
不仅在不同的数据库产品中,而且即使在相同数据库的不同版本中,存储公共数据库元数据的基础系统表都是不同的。例如,SQL Server 2005 使用在一个“sys”架构下的新表(例如,sys.tables)公开它的元数据,而 SQL Server 以前的版本使用元数据表(如 sysobjects£©来存储相同的数据。
-
不同的程序可能有不同的元数据视图。以一个例子来说,许多程序员抱怨 oracle 数据库中表的列表太长,因为大多数元数据 API 将“system”表与用户表混在一起。他们想要一个仅由他们定义的表组成的短列表。
-
是否根本不支持元数据,要提供多少元数据,应该完全取决于提供程序的编写者。
大 部分数据库 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:DataTable、SQLCommand 和 PrepareCollection。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 元数据集合。PrepareCommand 的 SqlMetaDataFactory 子类实现首先从 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 包含两个属性,QuoteIdentifier 和 UnquoteIdentifier,它们允许您在由 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操作类
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
{
///
///
public abstract class DbManagerSQL
{
//数据库连接字符串
protected static string connectionString = ConfigurationSettings.AppSettings[“ConnectionString”];
public DbManagerSQL()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
///
///
///
///
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);
}
}
}
}
///
///
///
///
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();
}
}
}
///
///
///
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);
}
}
}
///
///
///
///
///
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();
}
}
}
///
///
///
///
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();
}
}
}
///
///
///
///
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();
}
}
}
///
///
///
///
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区别不同浏览器写法
区别不同浏览器,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 手法
Mikel