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 { 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; } }
黄山市民网:https://www.huangshanshimin.com/