(四)数据持久化(基于YesSql)
程序员文章站
2023-10-16 20:50:05
ORM框架(持久化流程) session是事务 (transaction) 的工厂,处理session后,所有更改将自动刷新到数据库中。或者,如果要处理何时将更改刷新到数据库,即transaction将在session处理完后异步提交。session也可以取消事务。 新建两个项目,Data 与 Da ......
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;
}
}