==>>点击查看本系列文章目录
ORM框架(持久化流程)
session是事务 (transaction) 的工厂,处理session后,所有更改将自动刷新到数据库中。或者,如果要处理何时将更改刷新到数据库,即transaction将在session处理完后异步提交。session也可以取消事务。
新建两个项目,Data 与 Data.Abstractions, 其中 Data.Abstractions 为对外抽象接口(面向对象设计原则),并用Nuget添加程序包。
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 { IEnumerableGetFeatures(); IEnumerable GetFeatures(string[] featureIdsToLoad); IEnumerable GetFeatureDependencies(string featureId); IEnumerable 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
////// 数据库迁移管理 /// public interface IDataMigrationManager { //////返回具有至少一个数据迁移类的特性,并调用相应的升级方法 /// Task> GetFeaturesThatNeedUpdateAsync(); /// /// 运行所有需要更新的迁移。 /// Task UpdateAllFeaturesAsync(); ////// 将数据库更新为指定功能的最新版本 /// Task UpdateAsync(string feature); ////// 将数据库更新为指定功能的最新版本 /// Task UpdateAsync(IEnumerablefeatures); /// /// 执行脚本删除与该特性相关的任何信息 /// /// Task Uninstall(string feature); }
public interface IDbConnectionAccessor { ////// 创建数据库连接 /// ///DbConnection CreateConnection(); }
////// 数据库迁移工具,封装YesSql功能,直接修改数据库结构 /// public interface ISchemaBuilder { YesSql.Sql.ISchemaBuilder SchemaBuilder { get; set; } }
public static class DataAccess { public static IApplicationBuilder UseDataAccess(this IApplicationBuilder app) { return app.UseMiddleware(); } /// /// 添加数据库 /// /// /// 数据库类型,支持:SqlConnection,Sqlite,MySql,Postgres /// Sqlite为yessql.db文件所在路径,其他数据库为连接字符串 /// 表名前缀 ///public static IServiceCollection AddDataAccess(this IServiceCollection services, string databaseType, string connectionString, string tablePrefix = null) { services.AddScoped (); // 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 (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 (); store.RegisterIndexes(indexes); return store; }); services.AddScoped(sp => { var store = sp.GetService (); if (store == null) { return null; } var session = store.CreateSession(); var scopedServices = sp.GetServices (); session.RegisterIndexes(scopedServices.ToArray()); var httpContext = sp.GetRequiredService ()?.HttpContext; if (httpContext != null) { httpContext.Items[typeof(YesSql.ISession)] = session; } return session; }); services.AddTransient (); 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; } }