posts - 94, comments - 346, trackbacks - 10, articles - 0
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Fireasy.Data系列——数据库提供者的插件服务簇

Posted on 2012-04-19 00:54  faib  阅读(...)  评论(... 编辑 收藏

     前面已经介绍了,IProvider提供了一种插件式的服务接口,能够将一些扩展的功能附加在提供者中,因为IProvider由IDatabase所引用,因此,只要有IDatabase,就能够获得所有的扩展功能,那么本篇将介绍一下这些扩展服务如何与IProvider一起工作。

 

    首先看一下IProvider接口的定义:

 

    /// <summary>
    
/// 为不同的数据库类型提供创建工厂及插件服务。
    
/// </summary>
    public interface IProvider
    {
        /// <summary>
        
/// 获取提供者类型。
        
/// </summary>
        ProviderType ProviderType { get; }

        /// <summary>
        
/// 获取数据库提供者工厂。
        
/// </summary>
        DbProviderFactory DbProviderFactory { get; }

        /// <summary>
        
/// 获取相应的插件服务。
        
/// </summary>
        
/// <typeparam name="T">插件类型。</typeparam>
        
/// <returns></returns>
        T GetService<T>() where T : IProviderService;
        /// <summary>
        
/// 附加一个插件服务。
        
/// </summary>
        
/// <typeparam name="T"></typeparam>
        
/// <param name="service"></param>
        
/// <param name="overlay"></param>
        void RegisterService<T>(T service, bool overlay = falsewhere T : IProviderService;
        /// <summary>
        
/// 初始化所有插件服务。
        
/// </summary>
        
/// <param name="action"></param>
        void Initialize(Action<IProviderService> action);
        /// <summary>
        
/// 获取所有插件服务。
        
/// </summary>
        
/// <returns></returns>
        IEnumerable<IProviderService> GetServices();

        /// <summary>
        
/// 获取当前连接的参数。
        
/// </summary>
        
/// <returns></returns>
        ConnectionParameter GetConnectionParameter(ConnectionString connectionString);

    }

     本文着重关心的是IProviderServices的相关实现细节,因此其他内容不再赘述。

     接下来定义一个实现类,当然也是一个抽象类,具体还要由相应的数据库提供者来实现。

 

    /// <summary>
    
/// 基本的数据库提供者。
    
/// </summary>
    public abstract class BaseProvider : IProvider
    {
        private readonly Dictionary<string, IProviderService> m_plugs = new Dictionary<string, IProviderService>();

        /// <summary>
        
/// 表示 <see cref="DbProviderFactory"/> 对象。
        
/// </summary>
        protected DbProviderFactory Factory;
        private Action<IProviderService> m_action;

        /// <summary>
        
/// 初始化 <see cref="BaseProvider"/> 类的新实例。
        
/// </summary>
        protected BaseProvider()
        {
        }

        /// <summary>
        
/// 使用提供者名称初始化 <see cref="BaseProvider"/> 类的新实例。
        
/// </summary>
        
/// <param name="providerName"></param>
        protected BaseProvider(string providerName)
        {
            Factory = DbProviderFactories.GetFactory(providerName);
        }

        /// <summary>
        
/// 获取数据提供者类型。
        
/// </summary>
        public abstract ProviderType ProviderType { get; }

        /// <summary>
        
/// 获取数据库提供者工厂。
        
/// </summary>
        public virtual DbProviderFactory DbProviderFactory
        {
            get
            {
                if (Factory == null)
                {
                    throw new Exception("DbProviderFactory 为空,请检查 providerName 或相关的程序集是否存在。");
                }
                return Factory;
            }
        }

        /// <summary>
        
/// 获取相应的插件。
        
/// </summary>
        
/// <typeparam name="T">插件类型。</typeparam>
        
/// <returns></returns>
        public virtual T GetService<T>() where T : IProviderService
        {
            var key = typeof(T).GUID.ToString();
            if (m_plugs.ContainsKey(key))
            {
                return (T)m_plugs[key];
            }
            return default(T);
        }

        /// <summary>
        
/// 附加一个插件。
        
/// </summary>
        
/// <typeparam name="T"></typeparam>
        
/// <param name="provider"></param>
        
/// <param name="overwite"></param>
        public void RegisterService<T>(T provider, bool overwite = falsewhere T : IProviderService
        {
            var implType = provider.GetType().GetDirectImplementInterface(typeof(IProviderService));
            var key = implType.GUID.ToString();
            if (!m_plugs.ContainsKey(key))
            {
                m_plugs.Add(key, provider);
                if (m_action != null)
                {
                    m_action(provider);
                }
            }
            else if (overwite)
            {
                m_plugs[key] = provider;
                if (m_action != null)
                {
                    m_action(provider);
                }
            }
        }

        void IProvider.Initialize(Action<IProviderService> action)
        {
            if (action == null)
            {
                return;
            }
            m_action = action;
            foreach (var kvp in m_plugs)
            {
                action(kvp.Value);
            }
        }

        /// <summary>
        
/// 获取所有插件服务。
        
/// </summary>
        
/// <returns></returns>
        IEnumerable<IProviderService> IProvider.GetServices()
        {
            return m_plugs.Select(kvp => kvp.Value);
        }

        /// <summary>
        
/// 获取当前连接的参数。
        
/// </summary>
        
/// <returns></returns>
        public abstract ConnectionParameter GetConnectionParameter(ConnectionString connectionString);
    }

 

       着重在于RegisterService方法,为什么要用GetDirectImplementInterface方法呢?该方法用于从类型type中获得直接继承自IProviderServices接口的接口,呵呵,这个有点不清晰吧,就用前篇提到的IBatcherProvider接口为例来说吧,IBatcherProvider继承自IProviderServices,将我们用RegisterService方法注册一个IBatcherProvider的实现类时,实际上是获得了IBatcherProvider的类型,这主要是为了方便GetService方法的使用,我们想通过IProvider获得某种扩展服务的实例时,并不需要知道具体的实现类,而是使用GetService<IBatcherProvider>()这样的方式来获取。

       在不同数据库提供者的实现中,分别注册进不同的扩展服务:

 

    /// <summary>
    
/// MsSql数据库提供者。
    
/// </summary>
    public sealed class MsSqlProvider : BaseProvider
    {   
        /// <summary>
        
/// 提供 <see cref="MsSqlProvider"/> 的静态实例。
        
/// </summary>
        public readonly static MsSqlProvider Instance = new MsSqlProvider();

        /// <summary>
        
/// 初始化 <see cref="MsSqlProvider"/> 类的新实例。
        
/// </summary>
        public MsSqlProvider()
            : base ("System.Data.SqlClient")
        {
            RegisterService(new MsSqlBatcher());
            RegisterService(new MsSqlSyntax());
            RegisterService(new MsSqlSchema());
            RegisterService(new MsSqlBackup());
        }
    }

 

       然而,IProviderServices接口有一个上下文对象,该上下文是通过Initialize方法附加到扩展服务中的。在Database的构造函数中,我们可以看到:

 

        /// <summary>
        
/// 初始化 <see cref="Database"/> 类的新实例。
        
/// </summary>
        
/// <param name="connectionString">数据库连接字符串。</param>
        
/// <param name="provider">数据库提供者。</param>
        public Database (ConnectionString connectionString, IProvider provider)
            : this ()
        {
            Checker.ArgumentNull(provider, "provider");
            Provider = provider;
            ConnectionString = connectionString;
            var providerContext = new ServiceContext { Database = this };
            Provider.Initialize(p => p.ServiceContext = providerContext);
        }

       通过委托的方式进行了初始化,当然前提是,这部份扩展服务是在提供者的构造里注册的,如果后期注册的,则在RegisterService里由m_action进行调用处理了。

       这样,我们可以使用GetService来获取不同的扩展服务了:

 

var batcher = database.Provider.GetService<IBatcherProvider>();
var syntax = database.Provider.GetService<ISyntaxProvider>();
var schema = database.Provider.GetService<ISchemaProvider>();
var backup = database.Provider.GetService<IBackupProvider>();