惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
爱范儿
爱范儿
H
Help Net Security
V
Visual Studio Blog
J
Java Code Geeks
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
MyScale Blog
MyScale Blog
The Cloudflare Blog
Martin Fowler
Martin Fowler
D
Docker
腾讯CDC
F
Fortinet All Blogs
雷峰网
雷峰网
GbyAI
GbyAI
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
博客园 - 叶小钗

博客园 - faib

代码生成器(CodeBuilder) 2.9.4 稳定版 代码生成器(CodeBuilder) 2.9.3 稳定版 Fireasy新版本发布 Winform快速开发组件的实现(二) Winform快速开发组件的实现(一) 注意Activator.CreateInstance两个重载方法的性能 Fireasy.Data系列——发布测试版本 Fireasy.Data系列——线程内IDatabase的传递 Fireasy.Data系列——数据库架构的整合查询 Fireasy.Data系列——几种数据库的大数据批量插入 Fireasy.Data系列——底层结构 Fireasy.Data系列——概述 我想组建新的Entity框架 轻量的Json序列化 ReSharper 不为人知的罪恶选项 AxTools.VS10x.CodeMap注册机 3个月时间完成工作流项目 历时半年,发布最完整的代码生成器CodeBuilder最新版本 最新版本的CodeBuilder 1.0.0.1446
Fireasy.Data系列——数据库提供者的插件服务簇
faib · 2012-04-19 · via 博客园 - 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>();