hi,all,
项目中常常用到enterpriselibrary2006jan库中的daab,所以经常需要用ppt给员工说明一下daab配置文件中如何配置数据库连接字符串的。下面就是一些简单的文字描述:
第一小节:
什么是节处理器 (section handlers)
在配置文件里除了 常见的system.net、system.data等节点之外, 还可以自已写 xml 格式的配置元素,这些元素叫做节(section)。当然,如果你自己写一堆复杂的 xml 格式的标签,.net 自身是不知道如何解析的,因此这里就需要你在指定节的同时,告诉 .net 如何处理它们,也就是定义“节处理器”(section handlers)。
每一个自定义的节,都需要在 configsections 下面定义它们的节处理器。先来看一个例子:
<?xml version="1.0" encoding="utf-8" ?>
<section name="dataconfiguration"type="microsoft.practices.enterpriselibrary.data.configuration.databasesettings,microsoft.practices.enterpriselibrary.data, version=2.0.0.0, culture=neutral, publickeytoken=null" />
</configsections>
这就是定义说,如果发现在配置文件有“dataconfiguration”节点,那么就应该用assembly“microsoft.practices.enterpriselibrary.data”的“microsoft.practices.enterpriselibrary.data.configuration.databasesettings”类来处理。
第二小节,
为什么它能处理?
我们来看dataconfiguration节点中都定义了什么:
<dataconfiguration defaultdatabase="usp_authentication">
<add databasetype="microsoft.practices.enterpriselibrary.data.genericdatabase, microsoft.practices.enterpriselibrary.data, version=2.0.0.0, culture=neutral, publickeytoken=null" name="data.usp.mssql" />
</providermappings>
</dataconfiguration>
它包含了两个东西:
属性:defaultdatabase
和节点:providermappings
,如果daab写程序读取配置,需要处理这两个东西。
接下来我们打开enterprise library 2006.jan的data solution,看看microsoft.practices.enterpriselibrary.data.configuration.databasesettings是怎么定义的。
/// <remarks>
/// <para>the class maps to the <c>databasesettings</c> element in configuration.</para>
/// </remarks>
public class databasesettings : serializableconfigurationsection
enterprise library 的配置框架建立在 system.configuration 的基础之上,而且工作方式也与其非常相似。应用程序块的配置节派生自 microsoft.practices.enterpriselibrary.common.configuration.serializableconfigurationsection,而不是直接从 system.configuration.configurationsection 派生。
serializableconfigurationsection 也是microsoft.practices.enterpriselibrary.common.configuration下的类,是从configurationsection, ixmlserializable类继承可以看出是对configurationsection的扩展,而每个entlib应用程序块的配置节点都必须继承自此类,此类主要包括了对xml文件节点的操作方法。
{
private const string defaultdatabaseproperty = "defaultdatabase";
private const string dbprovidermappingsproperty = "providermappings";
/// <summary>
/// the name of the data configuration section.
/// </summary>
public const string sectionname = "dataconfiguration";
最重要的代码是:
public static databasesettings getdatabasesettings(iconfigurationsource configurationsource)
{
return (databasesettings)configurationsource.getsection(sectionname);
}
它的意义就是,从配置文件中指定dataconfiguration名的节点树把配置读取到configurationsection对象中。
之后就可以:
对于属性,它这么处理:
[configurationproperty(defaultdatabaseproperty, isrequired = false)]
public string defaultdatabase
get
{
return (string)this[defaultdatabaseproperty];
}
set
this[defaultdatabaseproperty] = value;
对于节点,它这么处理:
[configurationproperty(dbprovidermappingsproperty, isrequired = false)]
public namedelementcollection<dbprovidermapping> providermappings
return (namedelementcollection<dbprovidermapping>)base[dbprovidermappingsproperty];
示意如下:
第三步,
配置节点详解
我们在配置文件中用
<system.data>
<dbproviderfactories>
<add
name="sql server 2005"
invariant="data.usp.mssql"
description="an alias for the sqlprovider"
type="system.data.sqlclient.sqlclientfactory, system.data, version=2.0.0.0, culture=neutral, publickeytoken=b77a5c561934e089" />
</dbproviderfactories>
</system.data>
设定了database的provider,在这里可以指定很多种不同的provider,比如:
<add name="my generic database" invariant="myoledbdatabase" description="an alias for the oledbprovider" type="system.data.oledb.oledbfactory, system.data, version=2.0.0.0, culture=neutral, publickeytoken=b77a5c561934e089" />
此时要用自己定义的provider,就可以这么定义连接字符串:
<connectionstrings>
<add name="mytestconnectionstring" connectionstring="provider=microsoft.jet.oledb.4.0;data source=d:\my2005codes\testcode\accessdb.mdb;"
providername="myoledbdatabase" />
</connectionstrings>
当然,也可以不用在这里指定,而是后面连接字符串配置节点中直接指定已有的provider。
我们现在的连接字符串配置是:
<add
name="authentication"
providername="system.data.sqlclient"
connectionstring="server=11.168.1.22;database=db_authentication;uid=usp;pwd=de;" />
name="log"
providername="data.usp.mssql"
connectionstring="server=11.168.1.22;database=db_log;uid=logger;pwd=de;" />
那么,实际上这个“system.data.sqlclient”就是系统约定的provider名,用我们自定义的“data.usp.mssql”也可以达到同样的效果。
第四步,
当我们调用
databasefactory.createdatabase("authentication");
时,实际上就是命令daab用
<add
所指定的连接字符串去连数据库。
辅助参考蝈蝈俊的blog:
databasefactory.createdatabase 方法创建数据库实例的 逻辑过程
简单看一下 databasefactory.createdatabase 方法 是根据啥关系,来判断应该创建的是 database 抽象类的那个子类。
分析代码可知,这里的判断分三步:
主要代码看 databasecustomfactory.cs 文件的
public object createobject(ibuildercontext context, string name, iconfigurationsource configurationsource, configurationreflectioncache reflectioncache)方法。
第一步:
在链接字符串中,我们可以根据链接字符串的 name 获得 链接字符串的 providername 。
第二步:
如果 我们设置了 providername 的任何 影射关系, 则自动获得 这个映射的 dbprovidermapping ;
如果这个数据库访问者 没有被设置任何影射关系, 则 系统自动在默认提供的 sqldatabase、 oracledatabase 中匹配。
如果上述都没匹配出结果, 则 返回 genericdatabase 。
上述逻辑在 databaseconfigurationview.cs 文件中可以看到代码:
public dbprovidermapping getprovidermapping(string name, string dbprovidername)
databasesettings settings = this.databasesettings;
if (settings != null)
{
dbprovidermapping existingmapping = settings.providermappings.get(dbprovidername);
if (existingmapping != null)
return existingmapping;
}
dbprovidermapping defaultmapping = this.getdefaultmapping(name, dbprovidername);
if (defaultmapping != null)
return defaultmapping;
return this.getgenericmapping();
}
第三步
根据 dbprovidermapping 生成 database 抽象类的实例。
根据上述逻辑描述,我们就可以理解如下一个数据库的配置文件了。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configsections>
<section name="dataconfiguration" type="microsoft.practices.enterpriselibrary.data.configuration.databasesettings, microsoft.practices.enterpriselibrary.data, version=2.0.0.0, culture=neutral, publickeytoken=null" />
</configsections>
<dataconfiguration defaultdatabase="mytestconnectionstring">
<providermappings>
<add databasetype="microsoft.practices.enterpriselibrary.data.genericdatabase, microsoft.practices.enterpriselibrary.data, version=2.0.0.0, culture=neutral, publickeytoken=null"
name="genericdatabase" />
<add databasetype="microsoft.practices.enterpriselibrary.data.sql.sqldatabase, microsoft.practices.enterpriselibrary.data, version=2.0.0.0, culture=neutral, publickeytoken=null"
name="system.data.sqlclient" />
</providermappings>
</dataconfiguration>
<connectionstrings>
<add name="mytestconnectionstring" connectionstring="server=(local)\sqlexpress;database=entlibquickstarts;integrated security=true;"
providername="genericdatabase" />
<system.data>
<add name="my generic database" invariant="genericdatabase" description="an alias for the sqlprovider" type="system.data.sqlclient.sqlclientfactory, system.data, version=2.0.0.0, culture=neutral, publickeytoken=b77a5c561934e089" />
</configuration>
这个数据库配置文件生成的 database dbsvc = databasefactory.createdatabase();
dbsvc 必然是 microsoft.practices.enterpriselibrary.data.genericdatabase 类型的。
注意:
system.data 数据节 的 dbproviderfactories 配置节 是给配置文件中 connectionstrings 节的 providername 对应用的。
而 dataconfiguration 配置节的 providermappings 是给 生成 的 是那一个 database 抽象类的那一个实例用的。
参考资料:
<a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/entlibjan2006_dataaccessappblock.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/entlibjan2006_dataaccessappblock.asp</a>
<a href="http://blogs.msdn.com/tomholl/archive/2005/09/14/466298.aspx">http://blogs.msdn.com/tomholl/archive/2005/09/14/466298.aspx</a>
<a href="http://www.dotnetslackers.com/vb_net/re-9165_daab_in_enterprise_library_for_net_2_0.aspx">http://www.dotnetslackers.com/vb_net/re-9165_daab_in_enterprise_library_for_net_2_0.aspx</a>
郑昀 笔记 200703
推荐阅读: