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