天天看点

EnterpriseLibrary的DAAB如何灵活配置数据库的笔记

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];

示意如下:

EnterpriseLibrary的DAAB如何灵活配置数据库的笔记

第三步,

配置节点详解

我们在配置文件中用

<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

推荐阅读: