(四)數據持久化(基於YesSql)

==>>點擊查看本系列文章目錄

 

ORM框架(持久化流程)

session是事務 (transaction) 的工廠,處理session後,全部更改將自動刷新到數據庫中。或者,若是要處理什麼時候將更改刷新到數據庫,即transaction將在session處理完後異步提交。session也能夠取消事務html

新建兩個項目,Data 與 Data.Abstractions, 其中 Data.Abstractions 爲對外抽象接口(面向對象設計原則),並用Nuget添加程序包。sql

 

 

 

public interface IFeatureInfo
    {
        string Id { get; }
        string Name { get; }
        int Priority { get; }
        string Category { get; }
        string Description { get; }
        bool DefaultTenantOnly { get; }
        //IExtensionInfo Extension { get; }
        string[] Dependencies { get; }
    }

  

public interface IFeatureManager
    {
        IEnumerable<IFeatureInfo> GetFeatures();
        IEnumerable<IFeatureInfo> GetFeatures(string[] featureIdsToLoad);
        IEnumerable<IFeatureInfo> GetFeatureDependencies(string featureId);
        IEnumerable<IFeatureInfo> GetDependentFeatures(string featureId);
        IFeatureInfo GetFeatureForDependency(Type dependency);
        void TryAdd(Type type, IFeatureInfo feature);
    }

  

public class DatabaseProvider
    {
        public string Name { get; set; }
        public string Value { get; set; }
        public bool HasConnectionString { get; set; }
        public bool HasTablePrefix { get; set; }
        publi

  

/// <summary>
    /// 數據庫遷移管理
    /// </summary>
    public interface IDataMigrationManager
    {
        /// <summary>
        ///返回具備至少一個數據遷移類的特性,並調用相應的升級方法
        /// </summary>
        Task<IEnumerable<string>> GetFeaturesThatNeedUpdateAsync();

        /// <summary>
        /// 運行全部須要更新的遷移。
        /// </summary>
        Task UpdateAllFeaturesAsync();

        /// <summary>
        /// 將數據庫更新爲指定功能的最新版本
        /// </summary>
        Task UpdateAsync(string feature);

        /// <summary>
        /// 將數據庫更新爲指定功能的最新版本
        /// </summary>
        Task UpdateAsync(IEnumerable<string> features);

        /// <summary>
        /// 執行腳本刪除與該特性相關的任何信息
        /// </summary>
        /// <param name="feature"></param>
        Task Uninstall(string feature);
    }

  

public interface IDbConnectionAccessor
    {
        /// <summary>
        /// 建立數據庫鏈接
        /// </summary>
        /// <returns></returns>
        DbConnection CreateConnection();
    }

  

/// <summary>
    /// 數據庫遷移工具,封裝YesSql功能,直接修改數據庫結構
    /// </summary>
    public interface ISchemaBuilder
    {
        YesSql.Sql.ISchemaBuilder SchemaBuilder { get; set; }
    }

  

 

 

public static class DataAccess
    {
        public static IApplicationBuilder UseDataAccess(this IApplicationBuilder app)
        {
            return app.UseMiddleware<CommitSessionMiddleware>();
        }


        /// <summary>
        /// 添加數據庫
        /// </summary>
        /// <param name="services"></param>
        /// <param name="databaseType">數據庫類型,支持:SqlConnection,Sqlite,MySql,Postgres</param>
        /// <param name="connectionString">Sqlite爲yessql.db文件所在路徑,其餘數據庫爲鏈接字符串</param>
        /// <param name="tablePrefix">表名前綴</param>
        /// <returns></returns>
        public static IServiceCollection AddDataAccess(this IServiceCollection services, string databaseType, string connectionString, string tablePrefix = null)
        {
            services.AddScoped<IDataMigrationManager, DataMigrationManager>();

            // Adding supported databases
            services.TryAddDataProvider(name: "Sql Server", value: "SqlConnection", hasConnectionString: true, hasTablePrefix: true, isDefault: false);
            services.TryAddDataProvider(name: "Sqlite", value: "Sqlite", hasConnectionString: false, hasTablePrefix: false, isDefault: true);
            services.TryAddDataProvider(name: "MySql", value: "MySql", hasConnectionString: true, hasTablePrefix: true, isDefault: false);
            services.TryAddDataProvider(name: "Postgres", value: "Postgres", hasConnectionString: true, hasTablePrefix: true, isDefault: false);

            // Configuring data access
            services.AddSingleton<IStore>(sp =>
            {
                IConfiguration storeConfiguration = new YesSql.Configuration();

                switch (databaseType)
                {
                    case "SqlConnection":
                        storeConfiguration
                            .UseSqlServer(connectionString, IsolationLevel.ReadUncommitted)
                            .UseBlockIdGenerator();
                        break;
                    case "Sqlite":
                        var databaseFolder = connectionString;
                        var databaseFile = Path.Combine(databaseFolder, "yessql.db");
                        Directory.CreateDirectory(databaseFolder);
                        storeConfiguration
                            .UseSqLite($"Data Source={databaseFile};Cache=Shared", IsolationLevel.ReadUncommitted)
                            .UseDefaultIdGenerator();
                        break;
                    case "MySql":
                        storeConfiguration
                            .UseMySql(connectionString, IsolationLevel.ReadUncommitted)
                            .UseBlockIdGenerator();
                        break;
                    case "Postgres":
                        storeConfiguration
                            .UsePostgreSql(connectionString, IsolationLevel.ReadUncommitted)
                            .UseBlockIdGenerator();
                        break;
                    default:
                        throw new ArgumentException("Unknown database type: " + databaseType);
                }

                if (!string.IsNullOrWhiteSpace(tablePrefix))
                {
                    storeConfiguration = storeConfiguration.SetTablePrefix(tablePrefix + "_");
                }

                var store = StoreFactory.CreateAsync(storeConfiguration).GetAwaiter().GetResult();
                var indexes = sp.GetServices<IIndexProvider>();

                store.RegisterIndexes(indexes);

                return store;
            });

            services.AddScoped(sp =>
            {
                var store = sp.GetService<IStore>();

                if (store == null)
                {
                    return null;
                }

                var session = store.CreateSession();

                var scopedServices = sp.GetServices<IIndexProvider>();

                session.RegisterIndexes(scopedServices.ToArray());

                var httpContext = sp.GetRequiredService<IHttpContextAccessor>()?.HttpContext;

                if (httpContext != null)
                {
                    httpContext.Items[typeof(YesSql.ISession)] = session;
                }

                return session;
            });

            services.AddTransient<IDbConnectionAccessor, DbConnectionAccessor>();

            return services;
        }
    }

    public class CommitSessionMiddleware
    {
        private readonly RequestDelegate _next;

        public CommitSessionMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            await _next.Invoke(httpContext);

            // Don't resolve to prevent instantiating one in case of static sites
            var session = httpContext.Items[typeof(YesSql.ISession)] as YesSql.ISession;

            if (session != null)
            {
                await session.CommitAsync();
            }
        }
    }

  

 

public static class DataProvider
    {
        public static IServiceCollection TryAddDataProvider(this IServiceCollection services, string name, string value, bool hasConnectionString, bool hasTablePrefix, bool isDefault)
        {
            for (var i = services.Count - 1; i >= 0; i--)
            {
                var entry = services[i];
                if (entry.ImplementationInstance != null)
                {
                    var databaseProvider = entry.ImplementationInstance as DatabaseProvider;
                    if (databaseProvider != null && String.Equals(databaseProvider.Name, name, StringComparison.OrdinalIgnoreCase))
                    {
                        services.RemoveAt(i);
                    }
                }
            }

            services.AddSingleton(new DatabaseProvider { Name = name, Value = value, HasConnectionString = hasConnectionString, HasTablePrefix = hasTablePrefix, IsDefault = isDefault });

            return services;
        }
    }
相關文章
相關標籤/搜索