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


         前面已经介绍了,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>();
  • 相关阅读:
    从.Net到Java学习第十篇——Spring Boot文件上传和下载
    Access denied for user 'root'@'localhost' (using password:YES) Mysql5.7
    从.Net到Java学习第八篇——SpringBoot实现session共享和国际化
    从.Net到Java学习第九篇——SpringBoot下Thymeleaf
    从.Net到Java学习第七篇——SpringBoot Redis 缓存穿透
    从.Net到Java学习第六篇——SpringBoot+mongodb&Thymeleaf&模型验证
    从.Net到Java学习第五篇——Spring Boot &&Profile &&Swagger2
    从.Net到Java学习第四篇——spring boot+redis
    从.Net到Java学习第三篇——spring boot+mybatis+mysql
    从.Net到Java学习第一篇——开篇
  • 原文地址:https://www.cnblogs.com/faib/p/2456420.html
Copyright © 2020-2023  润新知