mirror of
https://github.com/anjoy8/Blog.Core.git
synced 2024-09-20 23:48:27 +08:00
🎨✨🎉 优化原有的DBS配置、新增数据库故障转移方案
1.优化原有的DBS配置,破坏性修改,原有的DBS配置在多库和读写分离无法兼容,配置写法不是合适,故此优化 2.新增数据库故障转移方案,例如主库挂了自动切换到备用库,备用库不会由程序维护,需要运维、dba去做数据库同步方案,比如Sqlserver事务日志传输等 故障转移方案兼容多种方式 1.数据库主从方案 在配置主从之后,需要将从库配置为备用链接就行了 一般就是:修改、写入、删除走主库,查询操作走从库,在主库挂了后则所有操作走从库 2.数据库主备方案 日常使用主数据库操作,备用库只是备份,只有主库挂了才会用备用库 从库和备库都属于slave库功能
This commit is contained in:
parent
dfa067d214
commit
0901de2fbf
|
@ -36,19 +36,19 @@ namespace Blog.Core.Controllers
|
|||
{
|
||||
var data = new MessageModel<string>() { success = true, msg = "" };
|
||||
data.response += @"file path is:C:\my-file\}";
|
||||
var isMuti = AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool();
|
||||
var isMuti = BaseDBConfig.IsMulti;
|
||||
if (Env.IsDevelopment())
|
||||
{
|
||||
data.response += $"Controller层生成:{FrameSeed.CreateControllers(_sqlSugarClient)} || ";
|
||||
|
||||
BaseDBConfig.MutiConnectionString.allDbs.ToList().ForEach(m =>
|
||||
BaseDBConfig.ValidConfig.ForEach(m =>
|
||||
{
|
||||
_sqlSugarClient.ChangeDatabase(m.ConnId.ToLower());
|
||||
data.response += $"库{m.ConnId}-Model层生成:{FrameSeed.CreateModels(_sqlSugarClient, m.ConnId, isMuti)} || ";
|
||||
data.response += $"库{m.ConnId}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, m.ConnId, isMuti)} || ";
|
||||
data.response += $"库{m.ConnId}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, m.ConnId, isMuti)} || ";
|
||||
data.response += $"库{m.ConnId}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, m.ConnId, isMuti)} || ";
|
||||
data.response += $"库{m.ConnId}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, m.ConnId, isMuti)} || ";
|
||||
_sqlSugarClient.ChangeDatabase(m.ConfigId.ToLower());
|
||||
data.response += $"库{m.ConfigId}-Model层生成:{FrameSeed.CreateModels(_sqlSugarClient, m.ConfigId, isMuti)} || ";
|
||||
data.response += $"库{m.ConfigId}-IRepositorys层生成:{FrameSeed.CreateIRepositorys(_sqlSugarClient, m.ConfigId, isMuti)} || ";
|
||||
data.response += $"库{m.ConfigId}-IServices层生成:{FrameSeed.CreateIServices(_sqlSugarClient, m.ConfigId, isMuti)} || ";
|
||||
data.response += $"库{m.ConfigId}-Repository层生成:{FrameSeed.CreateRepository(_sqlSugarClient, m.ConfigId, isMuti)} || ";
|
||||
data.response += $"库{m.ConfigId}-Services层生成:{FrameSeed.CreateServices(_sqlSugarClient, m.ConfigId, isMuti)} || ";
|
||||
});
|
||||
|
||||
// 切回主库
|
||||
|
@ -74,7 +74,7 @@ namespace Blog.Core.Controllers
|
|||
{
|
||||
ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
|
||||
|
||||
var isMuti = AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool();
|
||||
var isMuti = BaseDBConfig.IsMulti;
|
||||
var data = new MessageModel<string>() { success = true, msg = "" };
|
||||
if (Env.IsDevelopment())
|
||||
{
|
||||
|
@ -102,7 +102,7 @@ namespace Blog.Core.Controllers
|
|||
{
|
||||
ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
|
||||
|
||||
var isMuti = AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool();
|
||||
var isMuti = BaseDBConfig.IsMulti;
|
||||
var data = new MessageModel<string>() { success = true, msg = "" };
|
||||
if (Env.IsDevelopment())
|
||||
{
|
||||
|
@ -112,7 +112,7 @@ namespace Blog.Core.Controllers
|
|||
{
|
||||
data.success = false;
|
||||
data.msg = "当前不处于开发模式,代码生成不可用!";
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
/// <summary>
|
||||
|
@ -126,7 +126,7 @@ namespace Blog.Core.Controllers
|
|||
{
|
||||
ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
|
||||
|
||||
var isMuti = AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool();
|
||||
var isMuti = BaseDBConfig.IsMulti;
|
||||
var data = new MessageModel<string>() { success = true, msg = "" };
|
||||
if (Env.IsDevelopment())
|
||||
{
|
||||
|
@ -151,7 +151,7 @@ namespace Blog.Core.Controllers
|
|||
{
|
||||
ConnID = ConnID == null ? MainDb.CurrentDbConnId.ToLower() : ConnID;
|
||||
|
||||
var isMuti = AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool();
|
||||
var isMuti = BaseDBConfig.IsMulti;
|
||||
var data = new MessageModel<string>() { success = true, msg = "" };
|
||||
if (Env.IsDevelopment())
|
||||
{
|
||||
|
|
|
@ -219,7 +219,7 @@ namespace Blog.Core.Controllers
|
|||
{
|
||||
List<ApiDate> apiDates = new List<ApiDate>();
|
||||
|
||||
if (AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool())
|
||||
if (_applicationUserServices.IsEnable())
|
||||
{
|
||||
var users = await _applicationUserServices.Query(d => d.tdIsDelete == false);
|
||||
|
||||
|
|
|
@ -80,14 +80,17 @@
|
|||
"UseLoadTest": false
|
||||
},
|
||||
|
||||
// 请配置MainDB为你想要的主库的ConnId值,并设置对应的Enabled为true;
|
||||
// *** 单库操作,把 MutiDBEnabled 设为false ***;
|
||||
// *** 多库操作,把 MutiDBEnabled 设为true,其他的从库Enabled也为true **;
|
||||
// 具体配置看视频:https://www.bilibili.com/video/BV1BJ411B7mn?p=6
|
||||
//Log:日志库;
|
||||
"MainDB": "WMBLOG_SQLITE", //当前项目的主库,所对应的连接字符串的Enabled必须为true
|
||||
"MutiDBEnabled": true, //是否开启多库模式
|
||||
"CQRSEnabled": false, //是否开启读写分离模式,必须是单库模式,且数据库类型一致,比如都是SqlServer
|
||||
//优化DB配置、不会再区分单库多库
|
||||
//MainDb:标识当前项目的主库,所对应的连接字符串的Enabled必须为true
|
||||
//Log:标识日志库,所对应的连接字符串的Enabled必须为true
|
||||
//从库只需配置Slaves数组,要求数据库类型一致!,比如都是SqlServer
|
||||
//
|
||||
//新增,故障转移方案
|
||||
//如果主库挂了,会自动切换到备用连接(比如说主库+备用库)
|
||||
//备用连接的ConnId配置为主库的ConnId+数字即可,比如主库的ConnId为Main,那么备用连接的ConnId为Mian1
|
||||
//主库、备用库无需数据库类型一致!
|
||||
//备用库不会有程序维护,需要手动维护
|
||||
"MainDB": "Main", //当前项目的主库,所对应的连接字符串的Enabled必须为true
|
||||
"DBS": [
|
||||
/*
|
||||
对应下边的 DBType
|
||||
|
@ -100,24 +103,40 @@
|
|||
Kdbndp = 6,//人大金仓
|
||||
*/
|
||||
{
|
||||
"ConnId": "WMBLOG_SQLITE",
|
||||
"ConnId": "Main",
|
||||
"DBType": 2,
|
||||
"Enabled": true,
|
||||
"HitRate": 50, // 值越大,优先级越高
|
||||
"Connection": "WMBlog.db" //sqlite只写数据库名就行
|
||||
"Connection": "WMBlog.db", //sqlite只写数据库名就行
|
||||
"Slaves": [
|
||||
{
|
||||
"HitRate": 0,// 值越大,优先级越高 0不使用
|
||||
"Connection": "WMBlog2.db"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ConnId": "Main2",
|
||||
"DBType": 2,
|
||||
"Enabled": true,
|
||||
"Connection": "WMBlog3.db", //sqlite只写数据库名就行
|
||||
"Slaves": [
|
||||
{
|
||||
"HitRate": 0,// 值越大,优先级越高 0不使用
|
||||
"Connection": "WMBlog4.db"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ConnId": "Log", //日志库连接固定名称,不要改,其他的可以改
|
||||
"DBType": 2,
|
||||
"Enabled": true,
|
||||
"HitRate": 50, // 值越大,优先级越高
|
||||
"HitRate": 50,
|
||||
"Connection": "WMBlogLog.db" //sqlite只写数据库名就行
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_MSSQL_1",
|
||||
"DBType": 1,
|
||||
"Enabled": false,
|
||||
"HitRate": 40,
|
||||
"Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_1;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
|
||||
"ProviderName": "System.Data.SqlClient"
|
||||
},
|
||||
|
@ -125,7 +144,6 @@
|
|||
"ConnId": "WMBLOG_MSSQL_2",
|
||||
"DBType": 1,
|
||||
"Enabled": false,
|
||||
"HitRate": 30,
|
||||
"Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_2;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
|
||||
"ProviderName": "System.Data.SqlClient"
|
||||
},
|
||||
|
@ -133,35 +151,30 @@
|
|||
"ConnId": "WMBLOG_MYSQL",
|
||||
"DBType": 0,
|
||||
"Enabled": false,
|
||||
"HitRate": 20,
|
||||
"Connection": "server=localhost;Database=blog;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;"
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_MYSQL_2",
|
||||
"DBType": 0,
|
||||
"Enabled": false,
|
||||
"HitRate": 20,
|
||||
"Connection": "server=localhost;Database=blogcore001;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;"
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_ORACLE",
|
||||
"DBType": 3,
|
||||
"Enabled": false,
|
||||
"HitRate": 10,
|
||||
"Connection": "Data Source=127.0.0.1/ops;User ID=OPS;Password=123456;Persist Security Info=True;Connection Timeout=60;"
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_DM",
|
||||
"DBType": 5,
|
||||
"Enabled": false,
|
||||
"HitRate": 10,
|
||||
"Connection": "Server=xxxxx:5236;User Id=xxxxx;PWD=xxxxx;SCHEMA=TESTDBA;"
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_KDBNDP",
|
||||
"DBType": 6,
|
||||
"Enabled": false,
|
||||
"HitRate": 10,
|
||||
"Connection": "Server=127.0.0.1;Port=54321;UID=SYSTEM;PWD=system;database=SQLSUGAR4XTEST1;"
|
||||
}
|
||||
],
|
||||
|
|
23
Blog.Core.Common/DB/Aop/SqlSugarReuse.cs
Normal file
23
Blog.Core.Common/DB/Aop/SqlSugarReuse.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System.Linq;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Blog.Core.Common.DB.Aop;
|
||||
|
||||
public class SqlSugarReuse
|
||||
{
|
||||
public static void AutoChangeAvailableConnect(SqlSugarClient db)
|
||||
{
|
||||
if (db == null) return;
|
||||
if (db.Ado.IsValidConnection()) return;
|
||||
if (!BaseDBConfig.ReuseConfigs.Any()) return;
|
||||
|
||||
foreach (var connectionConfig in BaseDBConfig.ReuseConfigs)
|
||||
{
|
||||
var config = db.CurrentConnectionConfig.ConfigId;
|
||||
db.ChangeDatabase(connectionConfig.ConfigId);
|
||||
//移除旧的连接,只会在本次上下文移除,因为主库已经故障会导致多库事务无法使用
|
||||
db.RemoveConnection(config);
|
||||
if (db.Ado.IsValidConnection()) return;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +1,46 @@
|
|||
using SqlSugar;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Blog.Core.Common.DB
|
||||
{
|
||||
public class BaseDBConfig
|
||||
{
|
||||
public static readonly List<ConnectionConfig> AllConfigs = new(); //所有库配置
|
||||
public static readonly List<SlaveConnectionConfig> AllSlaveConfigs = new(); //从库配置
|
||||
public static List<ConnectionConfig> ValidConfig = new(); //有效的库连接(除去Log库)
|
||||
public static ConnectionConfig LogConfig; //日志库
|
||||
|
||||
/// <summary>
|
||||
/// 所有库配置
|
||||
/// </summary>
|
||||
public static readonly List<ConnectionConfig> AllConfigs = new();
|
||||
|
||||
/// <summary>
|
||||
/// 主库的备用连接配置
|
||||
/// </summary>
|
||||
public static readonly List<ConnectionConfig> ReuseConfigs = new();
|
||||
|
||||
/// <summary>
|
||||
/// 有效的库连接(除去Log库)
|
||||
/// </summary>
|
||||
public static List<ConnectionConfig> ValidConfig = new();
|
||||
|
||||
public static ConnectionConfig MainConfig;
|
||||
public static ConnectionConfig LogConfig; //日志库
|
||||
|
||||
public static bool IsMulti => ValidConfig.Count > 1;
|
||||
|
||||
/* 之前的单库操作已经删除,如果想要之前的代码,可以查看我的GitHub的历史记录
|
||||
* 目前是多库操作,默认加载的是appsettings.json设置为true的第一个db连接。
|
||||
*
|
||||
* 优化配置连接
|
||||
* 老的配置方式,再多库和从库中有些冲突
|
||||
* 直接在单个配置中可以配置从库
|
||||
*
|
||||
* 新增故障转移方案
|
||||
* 增加主库备用连接,配置方式为ConfigId为主库的ConfigId+随便数字 只要不重复就好
|
||||
*
|
||||
* 主库在无法连接后会自动切换到备用链接
|
||||
*/
|
||||
public static (List<MutiDBOperate> allDbs, List<MutiDBOperate> slaveDbs) MutiConnectionString => MutiInitConn();
|
||||
|
||||
|
||||
|
||||
private static string DifDBConnOfSecurity(params string[] conn)
|
||||
{
|
||||
|
@ -44,52 +66,13 @@ namespace Blog.Core.Common.DB
|
|||
{
|
||||
List<MutiDBOperate> listdatabase = AppSettings.app<MutiDBOperate>("DBS")
|
||||
.Where(i => i.Enabled).ToList();
|
||||
var mainDbId = AppSettings.app(new string[] { "MainDB" }).ObjToString();
|
||||
var mainDbId = AppSettings.app(new string[] {"MainDB"}).ObjToString();
|
||||
var mainDbModel = listdatabase.Single(d => d.ConnId == mainDbId);
|
||||
listdatabase.Remove(mainDbModel);
|
||||
listdatabase.Insert(0, mainDbModel);
|
||||
|
||||
foreach (var i in listdatabase)
|
||||
{
|
||||
SpecialDbString(i);
|
||||
}
|
||||
|
||||
List<MutiDBOperate> listdatabaseSimpleDB = new List<MutiDBOperate>(); //单库
|
||||
List<MutiDBOperate> listdatabaseSlaveDB = new List<MutiDBOperate>(); //从库
|
||||
|
||||
// 单库,且不开启读写分离,只保留一个
|
||||
if (!AppSettings.app(new string[] {"CQRSEnabled"}).ObjToBool() && !AppSettings.app(new string[] {"MutiDBEnabled"}).ObjToBool())
|
||||
{
|
||||
if (listdatabase.Count == 1)
|
||||
{
|
||||
return (listdatabase, listdatabaseSlaveDB);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dbFirst = listdatabase.FirstOrDefault(d => d.ConnId == AppSettings.app(new string[] {"MainDB"}).ObjToString());
|
||||
if (dbFirst == null)
|
||||
{
|
||||
dbFirst = listdatabase.FirstOrDefault();
|
||||
}
|
||||
|
||||
listdatabaseSimpleDB.Add(dbFirst);
|
||||
return (listdatabaseSimpleDB, listdatabaseSlaveDB);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 读写分离,且必须是单库模式,获取从库
|
||||
if (AppSettings.app(new string[] {"CQRSEnabled"}).ObjToBool() && !AppSettings.app(new string[] {"MutiDBEnabled"}).ObjToBool())
|
||||
{
|
||||
if (listdatabase.Count > 1)
|
||||
{
|
||||
listdatabaseSlaveDB = listdatabase.Where(d => d.ConnId != AppSettings.app(new string[] {"MainDB"}).ObjToString()).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (listdatabase, listdatabaseSlaveDB);
|
||||
//}
|
||||
foreach (var i in listdatabase) SpecialDbString(i);
|
||||
return (listdatabase, mainDbModel.Slaves);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -102,19 +85,23 @@ namespace Blog.Core.Common.DB
|
|||
{
|
||||
if (mutiDBOperate.DbType == DataBaseType.Sqlite)
|
||||
{
|
||||
mutiDBOperate.Connection = $"DataSource=" + Path.Combine(Environment.CurrentDirectory, mutiDBOperate.Connection);
|
||||
mutiDBOperate.Connection =
|
||||
$"DataSource=" + Path.Combine(Environment.CurrentDirectory, mutiDBOperate.Connection);
|
||||
}
|
||||
else if (mutiDBOperate.DbType == DataBaseType.SqlServer)
|
||||
{
|
||||
mutiDBOperate.Connection = DifDBConnOfSecurity(@"D:\my-file\dbCountPsw1_SqlserverConn.txt", mutiDBOperate.Connection);
|
||||
mutiDBOperate.Connection = DifDBConnOfSecurity(@"D:\my-file\dbCountPsw1_SqlserverConn.txt",
|
||||
mutiDBOperate.Connection);
|
||||
}
|
||||
else if (mutiDBOperate.DbType == DataBaseType.MySql)
|
||||
{
|
||||
mutiDBOperate.Connection = DifDBConnOfSecurity(@"D:\my-file\dbCountPsw1_MySqlConn.txt", mutiDBOperate.Connection);
|
||||
mutiDBOperate.Connection =
|
||||
DifDBConnOfSecurity(@"D:\my-file\dbCountPsw1_MySqlConn.txt", mutiDBOperate.Connection);
|
||||
}
|
||||
else if (mutiDBOperate.DbType == DataBaseType.Oracle)
|
||||
{
|
||||
mutiDBOperate.Connection = DifDBConnOfSecurity(@"D:\my-file\dbCountPsw1_OracleConn.txt", mutiDBOperate.Connection);
|
||||
mutiDBOperate.Connection =
|
||||
DifDBConnOfSecurity(@"D:\my-file\dbCountPsw1_OracleConn.txt", mutiDBOperate.Connection);
|
||||
}
|
||||
|
||||
return mutiDBOperate;
|
||||
|
@ -159,5 +146,10 @@ namespace Blog.Core.Common.DB
|
|||
/// 数据库类型
|
||||
/// </summary>
|
||||
public DataBaseType DbType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 从库
|
||||
/// </summary>
|
||||
public List<MutiDBOperate> Slaves { get; set; }
|
||||
}
|
||||
}
|
14
Blog.Core.Common/DB/Extension/DbEntityException.cs
Normal file
14
Blog.Core.Common/DB/Extension/DbEntityException.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using SqlSugar;
|
||||
|
||||
namespace Blog.Core.Common.DB.Extension;
|
||||
|
||||
public static class DbEntityException
|
||||
{
|
||||
public static object GetEntityTenant(this Type type)
|
||||
{
|
||||
var tenant = type.GetCustomAttribute<TenantAttribute>();
|
||||
return tenant?.configId;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,6 @@
|
|||
{
|
||||
public static class MainDb
|
||||
{
|
||||
public static string CurrentDbConnId = "1";
|
||||
public static string CurrentDbConnId = "Main";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Blog.Core
|
||||
|
@ -288,5 +289,12 @@ namespace Blog.Core
|
|||
{
|
||||
return JsonConvert.SerializeObject(value);
|
||||
}
|
||||
|
||||
public static bool AnyNoException<T>(this ICollection<T> source)
|
||||
{
|
||||
if (source == null) return false;
|
||||
|
||||
return source.Any() && source.All(s => s != null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,40 +41,33 @@ namespace Blog.Core.Common.Seed
|
|||
SeedDataFolder = Path.Combine(WebRootPath, SeedDataFolder);
|
||||
|
||||
Console.WriteLine("************ Blog.Core DataBase Set *****************");
|
||||
Console.WriteLine($"Is multi-DataBase: {AppSettings.app(new string[] { "MutiDBEnabled" })}");
|
||||
Console.WriteLine($"Is CQRS: {AppSettings.app(new string[] { "CQRSEnabled" })}");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"Master DB ConId: {myContext.Db.CurrentConnectionConfig.ConfigId}");
|
||||
Console.WriteLine($"Master DB Type: {myContext.Db.CurrentConnectionConfig.DbType}");
|
||||
Console.WriteLine($"Master DB ConnectString: {myContext.Db.CurrentConnectionConfig.ConnectionString}");
|
||||
Console.WriteLine();
|
||||
if (AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool())
|
||||
if (BaseDBConfig.MainConfig.SlaveConnectionConfigs.AnyNoException())
|
||||
{
|
||||
var slaveIndex = 0;
|
||||
BaseDBConfig.MutiConnectionString.allDbs.Where(x => x.ConnId != MainDb.CurrentDbConnId).ToList().ForEach(m =>
|
||||
var index = 0;
|
||||
BaseDBConfig.MainConfig.SlaveConnectionConfigs.ForEach(m =>
|
||||
{
|
||||
slaveIndex++;
|
||||
Console.WriteLine($"Slave{slaveIndex} DB ID: {m.ConnId}");
|
||||
Console.WriteLine($"Slave{slaveIndex} DB Type: {m.DbType}");
|
||||
Console.WriteLine($"Slave{slaveIndex} DB ConnectString: {m.Connection}");
|
||||
index++;
|
||||
Console.WriteLine($"Slave{index} DB HitRate: {m.HitRate}");
|
||||
Console.WriteLine($"Slave{index} DB ConnectString: {m.ConnectionString}");
|
||||
Console.WriteLine($"--------------------------------------");
|
||||
});
|
||||
}
|
||||
else if (AppSettings.app(new string[] { "CQRSEnabled" }).ObjToBool())
|
||||
else if (BaseDBConfig.ReuseConfigs.AnyNoException())
|
||||
{
|
||||
var slaveIndex = 0;
|
||||
BaseDBConfig.MutiConnectionString.slaveDbs.Where(x => x.ConnId != MainDb.CurrentDbConnId).ToList().ForEach(m =>
|
||||
var index = 0;
|
||||
BaseDBConfig.ReuseConfigs.ForEach(m =>
|
||||
{
|
||||
slaveIndex++;
|
||||
Console.WriteLine($"Slave{slaveIndex} DB ID: {m.ConnId}");
|
||||
Console.WriteLine($"Slave{slaveIndex} DB Type: {m.DbType}");
|
||||
Console.WriteLine($"Slave{slaveIndex} DB ConnectString: {m.Connection}");
|
||||
index++;
|
||||
Console.WriteLine($"Reuse{index} DB ID: {m.ConfigId}");
|
||||
Console.WriteLine($"Reuse{index} DB Type: {m.DbType}");
|
||||
Console.WriteLine($"Reuse{index} DB ConnectString: {m.ConnectionString}");
|
||||
Console.WriteLine($"--------------------------------------");
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
|
@ -97,7 +90,8 @@ namespace Blog.Core.Common.Seed
|
|||
Console.WriteLine("Create Tables...");
|
||||
|
||||
var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
|
||||
var referencedAssemblies = System.IO.Directory.GetFiles(path, "Blog.Core.Model.dll").Select(Assembly.LoadFrom).ToArray();
|
||||
var referencedAssemblies = System.IO.Directory.GetFiles(path, "Blog.Core.Model.dll")
|
||||
.Select(Assembly.LoadFrom).ToArray();
|
||||
var modelTypes = referencedAssemblies
|
||||
.SelectMany(a => a.DefinedTypes)
|
||||
.Select(type => type.AsType())
|
||||
|
@ -117,7 +111,7 @@ namespace Blog.Core.Common.Seed
|
|||
ConsoleHelper.WriteSuccessLine($"Tables created successfully!");
|
||||
Console.WriteLine();
|
||||
|
||||
if (AppSettings.app(new string[] { "AppSettings", "SeedDBDataEnabled" }).ObjToBool())
|
||||
if (AppSettings.app(new string[] {"AppSettings", "SeedDBDataEnabled"}).ObjToBool())
|
||||
{
|
||||
JsonSerializerSettings setting = new JsonSerializerSettings();
|
||||
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
|
||||
|
@ -143,7 +137,9 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<BlogArticle>().AnyAsync())
|
||||
{
|
||||
myContext.GetEntityDB<BlogArticle>().InsertRange(JsonHelper.ParseFormByJson<List<BlogArticle>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "BlogArticle"), Encoding.UTF8)));
|
||||
myContext.GetEntityDB<BlogArticle>().InsertRange(
|
||||
JsonHelper.ParseFormByJson<List<BlogArticle>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "BlogArticle"), Encoding.UTF8)));
|
||||
Console.WriteLine("Table:BlogArticle created success!");
|
||||
}
|
||||
else
|
||||
|
@ -158,7 +154,8 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<Modules>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<Modules>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "Modules"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<Modules>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "Modules"), Encoding.UTF8), setting);
|
||||
|
||||
myContext.GetEntityDB<Modules>().InsertRange(data);
|
||||
Console.WriteLine("Table:Modules created success!");
|
||||
|
@ -175,7 +172,8 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<Permission>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<Permission>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "Permission"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<Permission>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "Permission"), Encoding.UTF8), setting);
|
||||
|
||||
myContext.GetEntityDB<Permission>().InsertRange(data);
|
||||
Console.WriteLine("Table:Permission created success!");
|
||||
|
@ -192,7 +190,8 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<Role>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<Role>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "Role"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<Role>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "Role"), Encoding.UTF8), setting);
|
||||
//using var stream = new FileStream(Path.Combine(WebRootPath, "BlogCore.Data.excel", "Role.xlsx"), FileMode.Open);
|
||||
//var result = await importer.Import<Role>(stream);
|
||||
//var data = result.Data.ToList();
|
||||
|
@ -212,7 +211,9 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<RoleModulePermission>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<RoleModulePermission>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "RoleModulePermission"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<RoleModulePermission>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "RoleModulePermission"), Encoding.UTF8),
|
||||
setting);
|
||||
|
||||
myContext.GetEntityDB<RoleModulePermission>().InsertRange(data);
|
||||
Console.WriteLine("Table:RoleModulePermission created success!");
|
||||
|
@ -229,7 +230,8 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<Topic>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<Topic>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "Topic"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<Topic>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "Topic"), Encoding.UTF8), setting);
|
||||
|
||||
myContext.GetEntityDB<Topic>().InsertRange(data);
|
||||
Console.WriteLine("Table:Topic created success!");
|
||||
|
@ -246,7 +248,8 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<TopicDetail>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<TopicDetail>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "TopicDetail"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<TopicDetail>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "TopicDetail"), Encoding.UTF8), setting);
|
||||
|
||||
myContext.GetEntityDB<TopicDetail>().InsertRange(data);
|
||||
Console.WriteLine("Table:TopicDetail created success!");
|
||||
|
@ -263,7 +266,8 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<UserRole>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<UserRole>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "UserRole"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<UserRole>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "UserRole"), Encoding.UTF8), setting);
|
||||
|
||||
myContext.GetEntityDB<UserRole>().InsertRange(data);
|
||||
Console.WriteLine("Table:UserRole created success!");
|
||||
|
@ -280,7 +284,8 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<SysUserInfo>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<SysUserInfo>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "sysUserInfo"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<SysUserInfo>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "sysUserInfo"), Encoding.UTF8), setting);
|
||||
|
||||
myContext.GetEntityDB<SysUserInfo>().InsertRange(data);
|
||||
Console.WriteLine("Table:sysUserInfo created success!");
|
||||
|
@ -297,7 +302,8 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<TasksQz>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<TasksQz>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "TasksQz"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<TasksQz>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "TasksQz"), Encoding.UTF8), setting);
|
||||
|
||||
myContext.GetEntityDB<TasksQz>().InsertRange(data);
|
||||
Console.WriteLine("Table:TasksQz created success!");
|
||||
|
@ -326,7 +332,8 @@ namespace Blog.Core.Common.Seed
|
|||
|
||||
if (!await myContext.Db.Queryable<Department>().AnyAsync())
|
||||
{
|
||||
var data = JsonConvert.DeserializeObject<List<Department>>(FileHelper.ReadFile(string.Format(SeedDataFolder, "Department"), Encoding.UTF8), setting);
|
||||
var data = JsonConvert.DeserializeObject<List<Department>>(
|
||||
FileHelper.ReadFile(string.Format(SeedDataFolder, "Department"), Encoding.UTF8), setting);
|
||||
|
||||
myContext.GetEntityDB<Department>().InsertRange(data);
|
||||
Console.WriteLine("Table:Department created success!");
|
||||
|
@ -367,7 +374,8 @@ namespace Blog.Core.Common.Seed
|
|||
.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass)
|
||||
.Where(u =>
|
||||
{
|
||||
var esd = u.GetInterfaces().FirstOrDefault(i => i.HasImplementedRawGeneric(typeof(IEntitySeedData<>)));
|
||||
var esd = u.GetInterfaces()
|
||||
.FirstOrDefault(i => i.HasImplementedRawGeneric(typeof(IEntitySeedData<>)));
|
||||
if (esd is null)
|
||||
{
|
||||
return false;
|
||||
|
@ -441,11 +449,13 @@ namespace Blog.Core.Common.Seed
|
|||
logDb.DbMaintenance.CreateDatabase();
|
||||
ConsoleHelper.WriteSuccessLine($"Log Database created successfully!");
|
||||
var path = AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory;
|
||||
var referencedAssemblies = System.IO.Directory.GetFiles(path, "Blog.Core.Model.dll").Select(Assembly.LoadFrom).ToArray();
|
||||
var referencedAssemblies = System.IO.Directory.GetFiles(path, "Blog.Core.Model.dll")
|
||||
.Select(Assembly.LoadFrom).ToArray();
|
||||
var modelTypes = referencedAssemblies
|
||||
.SelectMany(a => a.DefinedTypes)
|
||||
.Select(type => type.AsType())
|
||||
.Where(x => x.IsClass && x.Namespace != null && x.Namespace.StartsWith("Blog.Core.Model.Logs")).ToList();
|
||||
.Where(x => x.IsClass && x.Namespace != null && x.Namespace.StartsWith("Blog.Core.Model.Logs"))
|
||||
.ToList();
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
|
||||
var tables = logDb.DbMaintenance.GetTableInfoList();
|
||||
|
@ -482,7 +492,8 @@ namespace Blog.Core.Common.Seed
|
|||
/// <returns></returns>
|
||||
public static async Task TenantSeedAsync(MyContext myContext)
|
||||
{
|
||||
var tenants = await myContext.Db.Queryable<SysTenant>().Where(s => s.TenantType == TenantTypeEnum.Db).ToListAsync();
|
||||
var tenants = await myContext.Db.Queryable<SysTenant>().Where(s => s.TenantType == TenantTypeEnum.Db)
|
||||
.ToListAsync();
|
||||
if (tenants.Any())
|
||||
{
|
||||
Console.WriteLine($@"Init Multi Tenant Db");
|
||||
|
@ -493,7 +504,8 @@ namespace Blog.Core.Common.Seed
|
|||
}
|
||||
}
|
||||
|
||||
tenants = await myContext.Db.Queryable<SysTenant>().Where(s => s.TenantType == TenantTypeEnum.Tables).ToListAsync();
|
||||
tenants = await myContext.Db.Queryable<SysTenant>().Where(s => s.TenantType == TenantTypeEnum.Tables)
|
||||
.ToListAsync();
|
||||
if (tenants.Any())
|
||||
{
|
||||
await InitTenantSeedAsync(myContext, tenants);
|
||||
|
@ -526,7 +538,8 @@ namespace Blog.Core.Common.Seed
|
|||
await TenantSeedDataAsync(myContext.Db, TenantTypeEnum.Tables);
|
||||
}
|
||||
|
||||
ConsoleHelper.WriteSuccessLine($"Init Multi Tenant Tables : {myContext.Db.CurrentConnectionConfig.ConfigId} created successfully!");
|
||||
ConsoleHelper.WriteSuccessLine(
|
||||
$"Init Multi Tenant Tables : {myContext.Db.CurrentConnectionConfig.ConfigId} created successfully!");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -580,7 +593,8 @@ namespace Blog.Core.Common.Seed
|
|||
.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass)
|
||||
.Where(u =>
|
||||
{
|
||||
var esd = u.GetInterfaces().FirstOrDefault(i => i.HasImplementedRawGeneric(typeof(IEntitySeedData<>)));
|
||||
var esd = u.GetInterfaces()
|
||||
.FirstOrDefault(i => i.HasImplementedRawGeneric(typeof(IEntitySeedData<>)));
|
||||
if (esd is null)
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -7,6 +7,7 @@ using Microsoft.Extensions.Hosting;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Blog.Core.Common.DB;
|
||||
|
||||
namespace Blog.Core.Extensions
|
||||
{
|
||||
|
@ -189,18 +190,8 @@ namespace Blog.Core.Extensions
|
|||
ConsoleHelper.WriteSuccessLine($"EventBus: True");
|
||||
}
|
||||
|
||||
// 多库
|
||||
if (!AppSettings.app(new string[] { "MutiDBEnabled" }).ObjToBool())
|
||||
{
|
||||
Console.WriteLine($"Is multi-DataBase: False");
|
||||
}
|
||||
else
|
||||
{
|
||||
ConsoleHelper.WriteSuccessLine($"Is multi-DataBase: True");
|
||||
}
|
||||
|
||||
// 读写分离
|
||||
if (!AppSettings.app(new string[] { "CQRSEnabled" }).ObjToBool())
|
||||
if (!BaseDBConfig.MainConfig.SlaveConnectionConfigs.AnyNoException())
|
||||
{
|
||||
Console.WriteLine($"Is CQRS: False");
|
||||
}
|
||||
|
@ -235,8 +226,7 @@ namespace Blog.Core.Extensions
|
|||
new string[] { "RabbitMQ消息列队", AppSettings.app("RabbitMQ", "Enabled") },
|
||||
new string[] { "事件总线(必须开启消息列队)", AppSettings.app("EventBus", "Enabled") },
|
||||
new string[] { "redis消息队列", AppSettings.app("Startup", "RedisMq", "Enabled") },
|
||||
new string[] { "是否多库", AppSettings.app("MutiDBEnabled") },
|
||||
new string[] { "读写分离", AppSettings.app("CQRSEnabled") },
|
||||
new string[] { "读写分离", BaseDBConfig.MainConfig.SlaveConnectionConfigs.AnyNoException()? "True" : "False" },
|
||||
};
|
||||
|
||||
new ConsoleTable()
|
||||
|
|
|
@ -9,6 +9,7 @@ using SqlSugar;
|
|||
using StackExchange.Profiling;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Blog.Core.Common.Caches;
|
||||
using Blog.Core.Common.Core;
|
||||
|
@ -30,16 +31,10 @@ namespace Blog.Core.Extensions
|
|||
if (services == null) throw new ArgumentNullException(nameof(services));
|
||||
|
||||
// 默认添加主数据库连接
|
||||
MainDb.CurrentDbConnId = AppSettings.app(new string[] { "MainDB" });
|
||||
|
||||
BaseDBConfig.MutiConnectionString.slaveDbs.ForEach(s =>
|
||||
if (!AppSettings.app("MainDB").IsNullOrEmpty())
|
||||
{
|
||||
BaseDBConfig.AllSlaveConfigs.Add(new SlaveConnectionConfig()
|
||||
{
|
||||
HitRate = s.HitRate,
|
||||
ConnectionString = s.Connection
|
||||
});
|
||||
});
|
||||
MainDb.CurrentDbConnId = AppSettings.app("MainDB");
|
||||
}
|
||||
|
||||
BaseDBConfig.MutiConnectionString.allDbs.ForEach(m =>
|
||||
{
|
||||
|
@ -47,7 +42,7 @@ namespace Blog.Core.Extensions
|
|||
{
|
||||
ConfigId = m.ConnId.ObjToString().ToLower(),
|
||||
ConnectionString = m.Connection,
|
||||
DbType = (DbType)m.DbType,
|
||||
DbType = (DbType) m.DbType,
|
||||
IsAutoCloseConnection = true,
|
||||
// Check out more information: https://github.com/anjoy8/Blog.Core/issues/122
|
||||
//IsShardSameThread = false,
|
||||
|
@ -58,7 +53,11 @@ namespace Blog.Core.Extensions
|
|||
SqlServerCodeFirstNvarchar = true,
|
||||
},
|
||||
// 从库
|
||||
SlaveConnectionConfigs = BaseDBConfig.AllSlaveConfigs,
|
||||
SlaveConnectionConfigs = m.Slaves?.Where(s => s.HitRate > 0).Select(s => new SlaveConnectionConfig
|
||||
{
|
||||
ConnectionString = s.Connection,
|
||||
HitRate = s.HitRate
|
||||
}).ToList(),
|
||||
// 自定义特性
|
||||
ConfigureExternalServices = new ConfigureExternalServices()
|
||||
{
|
||||
|
@ -79,6 +78,16 @@ namespace Blog.Core.Extensions
|
|||
}
|
||||
else
|
||||
{
|
||||
if (string.Equals(SqlSugarConst.LogConfigId, MainDb.CurrentDbConnId,
|
||||
StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
BaseDBConfig.MainConfig = config;
|
||||
}
|
||||
|
||||
//复用连接
|
||||
if (m.ConnId.ToLower().StartsWith(SqlSugarConst.LogConfigId.ToLower()))
|
||||
BaseDBConfig.ReuseConfigs.Add(config);
|
||||
|
||||
BaseDBConfig.ValidConfig.Add(config);
|
||||
}
|
||||
|
||||
|
@ -98,12 +107,14 @@ namespace Blog.Core.Extensions
|
|||
{
|
||||
BaseDBConfig.ValidConfig.ForEach(config =>
|
||||
{
|
||||
var dbProvider = db.GetConnectionScope((string)config.ConfigId);
|
||||
var dbProvider = db.GetConnectionScope((string) config.ConfigId);
|
||||
|
||||
// 打印SQL语句
|
||||
dbProvider.Aop.OnLogExecuting = (s, parameters) =>
|
||||
{
|
||||
SqlSugarAop.OnLogExecuting(dbProvider, App.User?.Name.ObjToString(), ExtractTableName(s), Enum.GetName(typeof(SugarActionType), dbProvider.SugarActionType), s, parameters, config);
|
||||
SqlSugarAop.OnLogExecuting(dbProvider, App.User?.Name.ObjToString(), ExtractTableName(s),
|
||||
Enum.GetName(typeof(SugarActionType), dbProvider.SugarActionType), s, parameters,
|
||||
config);
|
||||
};
|
||||
|
||||
// 数据审计
|
||||
|
@ -114,6 +125,8 @@ namespace Blog.Core.Extensions
|
|||
// 配置实体数据权限
|
||||
RepositorySetting.SetTenantEntityFilter(dbProvider);
|
||||
});
|
||||
//故障转移,检查主库链接自动切换备用连接
|
||||
SqlSugarReuse.AutoChangeAvailableConnect(db);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
using Blog.Core.IServices.BASE;
|
||||
using System.Threading.Tasks;
|
||||
using Blog.Core.IServices.BASE;
|
||||
using Blog.Core.Model.IDS4DbModels;
|
||||
|
||||
namespace Blog.Core.IServices
|
||||
{
|
||||
public partial interface IApplicationUserServices : IBaseServices<ApplicationUser>
|
||||
{
|
||||
bool IsEnable();
|
||||
}
|
||||
}
|
|
@ -27,21 +27,14 @@ namespace Blog.Core.Repository.Base
|
|||
{
|
||||
ISqlSugarClient db = _dbBase;
|
||||
|
||||
/* 如果要开启多库支持,
|
||||
* 1、在appsettings.json 中开启MutiDBEnabled节点为true,必填
|
||||
* 2、设置一个主连接的数据库ID,节点MainDB,对应的连接字符串的Enabled也必须true,必填
|
||||
*/
|
||||
if (AppSettings.app(new[] { "MutiDBEnabled" }).ObjToBool())
|
||||
//修改使用 model备注字段作为切换数据库条件,使用sqlsugar TenantAttribute存放数据库ConnId
|
||||
//参考 https://www.donet5.com/Home/Doc?typeId=2246
|
||||
var tenantAttr = typeof(TEntity).GetCustomAttribute<TenantAttribute>();
|
||||
if (tenantAttr != null)
|
||||
{
|
||||
//修改使用 model备注字段作为切换数据库条件,使用sqlsugar TenantAttribute存放数据库ConnId
|
||||
//参考 https://www.donet5.com/Home/Doc?typeId=2246
|
||||
var tenantAttr = typeof(TEntity).GetCustomAttribute<TenantAttribute>();
|
||||
if (tenantAttr != null)
|
||||
{
|
||||
//统一处理 configId 小写
|
||||
db = _dbBase.GetConnectionScope(tenantAttr.configId.ToString().ToLower());
|
||||
return db;
|
||||
}
|
||||
//统一处理 configId 小写
|
||||
db = _dbBase.GetConnectionScope(tenantAttr.configId.ToString().ToLower());
|
||||
return db;
|
||||
}
|
||||
|
||||
//多租户
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using Blog.Core.IRepository.Base;
|
||||
using System.Threading.Tasks;
|
||||
using Blog.Core.Common.DB;
|
||||
using Blog.Core.Common.DB.Extension;
|
||||
using Blog.Core.IRepository.Base;
|
||||
using Blog.Core.Model.IDS4DbModels;
|
||||
using Blog.Core.Services.BASE;
|
||||
|
||||
|
@ -6,6 +9,10 @@ namespace Blog.Core.IServices
|
|||
{
|
||||
public class ApplicationUserServices : BaseServices<ApplicationUser>, IApplicationUserServices
|
||||
{
|
||||
|
||||
public bool IsEnable()
|
||||
{
|
||||
var configId = typeof(ApplicationUser).GetEntityTenant();
|
||||
return Db.AsTenant().IsAnyConnection(configId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,13 +11,6 @@
|
|||
<None Remove="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
|
@ -38,6 +31,14 @@
|
|||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="appsettings.json">
|
||||
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ProjectExtensions><VisualStudio><UserProperties appsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,30 +1,26 @@
|
|||
{
|
||||
"urls": "http://*:9291", //web服务端口,如果用IIS部署,把这个去掉
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information", //加入Default否则log4net本地写入不了日志
|
||||
"Blog.Core.AuthHelper.ApiResponseHandler": "Error"
|
||||
},
|
||||
"Debug": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Warning"
|
||||
"Serilog": {
|
||||
"MinimumLevel": {
|
||||
"Default": "Debug",
|
||||
"Override": {
|
||||
"Microsoft": "Information",
|
||||
"Microsoft.AspNetCore": "Warning",
|
||||
"System": "Warning",
|
||||
"System.Net.Http.HttpClient": "Warning",
|
||||
"Hangfire": "Information",
|
||||
"Magicodes": "Warning",
|
||||
"DotNetCore.CAP": "Information",
|
||||
"Savorboard.CAP": "Information",
|
||||
"Quartz": "Information"
|
||||
}
|
||||
},
|
||||
"Console": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Debug"
|
||||
}
|
||||
},
|
||||
"Log4Net": {
|
||||
"Name": "Blog.Core"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Redis": {
|
||||
"ConnectionString": "127.0.0.1:6319,password=admin"
|
||||
"Enable": false,
|
||||
"ConnectionString": "127.0.0.1:6379",
|
||||
"InstanceName": "" //前缀
|
||||
},
|
||||
"RabbitMQ": {
|
||||
"Enabled": false,
|
||||
|
@ -48,24 +44,34 @@
|
|||
"CachingAOP": {
|
||||
"Enabled": true
|
||||
},
|
||||
"LogToDb": true,
|
||||
"LogAOP": {
|
||||
"Enabled": false
|
||||
"Enabled": false,
|
||||
"LogToFile": {
|
||||
"Enabled": true
|
||||
},
|
||||
"LogToDB": {
|
||||
"Enabled": true
|
||||
}
|
||||
},
|
||||
"TranAOP": {
|
||||
"Enabled": true
|
||||
},
|
||||
"UserAuditAOP": {
|
||||
"Enabled": false
|
||||
},
|
||||
"SqlAOP": {
|
||||
"Enabled": true,
|
||||
"OutToLogFile": {
|
||||
"Enabled": false
|
||||
"LogToFile": {
|
||||
"Enabled": true
|
||||
},
|
||||
"OutToConsole": {
|
||||
"LogToDB": {
|
||||
"Enabled": true
|
||||
},
|
||||
"LogToConsole": {
|
||||
"Enabled": true
|
||||
}
|
||||
},
|
||||
"LogToDb": {
|
||||
"Enabled": true
|
||||
},
|
||||
"Date": "2018-08-28",
|
||||
"SeedDBEnabled": true, //只生成表结构
|
||||
"SeedDBDataEnabled": true, //生成表,并初始化数据
|
||||
|
@ -74,14 +80,17 @@
|
|||
"UseLoadTest": false
|
||||
},
|
||||
|
||||
// 请配置MainDB为你想要的主库的ConnId值,并设置对应的Enabled为true;
|
||||
// *** 单库操作,把 MutiDBEnabled 设为false ***;
|
||||
// *** 多库操作,把 MutiDBEnabled 设为true,其他的从库Enabled也为true **;
|
||||
// 具体配置看视频:https://www.bilibili.com/video/BV1BJ411B7mn?p=6
|
||||
|
||||
"MainDB": "WMBLOG_SQLITE", //当前项目的主库,所对应的连接字符串的Enabled必须为true
|
||||
"MutiDBEnabled": false, //是否开启多库模式
|
||||
"CQRSEnabled": false, //是否开启读写分离模式,必须是单库模式,且数据库类型一致,比如都是SqlServer
|
||||
//优化DB配置、不会再区分单库多库
|
||||
//MainDb:标识当前项目的主库,所对应的连接字符串的Enabled必须为true
|
||||
//Log:标识日志库,所对应的连接字符串的Enabled必须为true
|
||||
//从库只需配置Slaves数组,要求数据库类型一致!,比如都是SqlServer
|
||||
//
|
||||
//新增,故障转移方案
|
||||
//如果主库挂了,会自动切换到备用连接(比如说主库+备用库)
|
||||
//备用连接的ConnId配置为主库的ConnId+数字即可,比如主库的ConnId为Main,那么备用连接的ConnId为Mian1
|
||||
//主库、备用库无需数据库类型一致!
|
||||
//备用库不会有程序维护,需要手动维护
|
||||
"MainDB": "Main", //当前项目的主库,所对应的连接字符串的Enabled必须为true
|
||||
"DBS": [
|
||||
/*
|
||||
对应下边的 DBType
|
||||
|
@ -94,17 +103,40 @@
|
|||
Kdbndp = 6,//人大金仓
|
||||
*/
|
||||
{
|
||||
"ConnId": "WMBLOG_SQLITE",
|
||||
"ConnId": "Main",
|
||||
"DBType": 2,
|
||||
"Enabled": true,
|
||||
"HitRate": 50, // 值越大,优先级越高
|
||||
"Connection": "WMBlog.db" //sqlite只写数据库名就行
|
||||
"Connection": "WMBlog.db", //sqlite只写数据库名就行
|
||||
"Slaves": [
|
||||
{
|
||||
"HitRate": 0,// 值越大,优先级越高 0不使用
|
||||
"Connection": "WMBlog2.db"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ConnId": "Main2",
|
||||
"DBType": 2,
|
||||
"Enabled": true,
|
||||
"Connection": "WMBlog3.db", //sqlite只写数据库名就行
|
||||
"Slaves": [
|
||||
{
|
||||
"HitRate": 0,// 值越大,优先级越高 0不使用
|
||||
"Connection": "WMBlog4.db"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ConnId": "Log", //日志库连接固定名称,不要改,其他的可以改
|
||||
"DBType": 2,
|
||||
"Enabled": true,
|
||||
"HitRate": 50,
|
||||
"Connection": "WMBlogLog.db" //sqlite只写数据库名就行
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_MSSQL_1",
|
||||
"DBType": 1,
|
||||
"Enabled": false,
|
||||
"HitRate": 40,
|
||||
"Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_1;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
|
||||
"ProviderName": "System.Data.SqlClient"
|
||||
},
|
||||
|
@ -112,7 +144,6 @@
|
|||
"ConnId": "WMBLOG_MSSQL_2",
|
||||
"DBType": 1,
|
||||
"Enabled": false,
|
||||
"HitRate": 30,
|
||||
"Connection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=WMBLOG_MSSQL_2;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
|
||||
"ProviderName": "System.Data.SqlClient"
|
||||
},
|
||||
|
@ -120,35 +151,30 @@
|
|||
"ConnId": "WMBLOG_MYSQL",
|
||||
"DBType": 0,
|
||||
"Enabled": false,
|
||||
"HitRate": 20,
|
||||
"Connection": "server=.;Database=ddd;Uid=root;Pwd=123456;Port=10060;Allow User Variables=True;"
|
||||
"Connection": "server=localhost;Database=blog;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;"
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_MYSQL_2",
|
||||
"DBType": 0,
|
||||
"Enabled": true,
|
||||
"HitRate": 20,
|
||||
"Connection": "server=.;Database=blogcore001;Uid=root;Pwd=123456;Port=3096;Allow User Variables=True;"
|
||||
"Enabled": false,
|
||||
"Connection": "server=localhost;Database=blogcore001;Uid=root;Pwd=root;Port=3306;Allow User Variables=True;"
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_ORACLE",
|
||||
"DBType": 3,
|
||||
"Enabled": false,
|
||||
"HitRate": 10,
|
||||
"Connection": "Data Source=127.0.0.1/ops;User ID=OPS;Password=123456;Persist Security Info=True;Connection Timeout=60;"
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_DM",
|
||||
"DBType": 5,
|
||||
"Enabled": false,
|
||||
"HitRate": 10,
|
||||
"Connection": "PORT=5236;DATABASE=DAMENG;HOST=localhost;PASSWORD=SYSDBA;USER ID=SYSDBA;"
|
||||
"Connection": "Server=xxxxx:5236;User Id=xxxxx;PWD=xxxxx;SCHEMA=TESTDBA;"
|
||||
},
|
||||
{
|
||||
"ConnId": "WMBLOG_KDBNDP",
|
||||
"DBType": 6,
|
||||
"Enabled": true,
|
||||
"HitRate": 10,
|
||||
"Enabled": false,
|
||||
"Connection": "Server=127.0.0.1;Port=54321;UID=SYSTEM;PWD=system;database=SQLSUGAR4XTEST1;"
|
||||
}
|
||||
],
|
||||
|
@ -163,12 +189,13 @@
|
|||
"Database": "BlogCoreDb"
|
||||
},
|
||||
"Startup": {
|
||||
"Domain": "http://localhost:9291",
|
||||
"Cors": {
|
||||
"PolicyName": "CorsIpAccess", //策略名称
|
||||
"EnableAllIPs": false, //当为true时,开放所有IP均可访问。
|
||||
// 支持多个域名端口,注意端口号后不要带/斜杆:比如localhost:8000/,是错的
|
||||
// 注意,http://127.0.0.1:1818 和 http://localhost:1818 是不一样的
|
||||
"IPs": "http://127.0.0.1:2364,http://localhost:2364"
|
||||
"IPs": "http://127.0.0.1:2364,http://localhost:2364,http://127.0.0.1:6688,http://localhost:6688"
|
||||
},
|
||||
"AppConfigAlert": {
|
||||
"Enabled": true
|
||||
|
@ -179,6 +206,12 @@
|
|||
"AuthorizationUrl": "http://localhost:5004", // 认证中心域名
|
||||
"ApiName": "blog.core.api" // 资源服务器
|
||||
},
|
||||
"Authing": {
|
||||
"Enabled": false,
|
||||
"Issuer": "https://uldr24esx31h-demo.authing.cn/oidc",
|
||||
"Audience": "63d51c4205c2849803be5178",
|
||||
"JwksUri": "https://uldr24esx31h-demo.authing.cn/oidc/.well-known/jwks.json"
|
||||
},
|
||||
"RedisMq": {
|
||||
"Enabled": false //redis 消息队列
|
||||
},
|
||||
|
@ -191,17 +224,38 @@
|
|||
},
|
||||
"Middleware": {
|
||||
"RequestResponseLog": {
|
||||
"Enabled": false
|
||||
"Enabled": true,
|
||||
"LogToFile": {
|
||||
"Enabled": true
|
||||
},
|
||||
"LogToDB": {
|
||||
"Enabled": true
|
||||
}
|
||||
},
|
||||
"IPLog": {
|
||||
"Enabled": true
|
||||
"Enabled": true,
|
||||
"LogToFile": {
|
||||
"Enabled": true
|
||||
},
|
||||
"LogToDB": {
|
||||
"Enabled": true
|
||||
}
|
||||
},
|
||||
"RecordAccessLogs": {
|
||||
"Enabled": true,
|
||||
"LogToFile": {
|
||||
"Enabled": true
|
||||
},
|
||||
"LogToDB": {
|
||||
"Enabled": true
|
||||
},
|
||||
"IgnoreApis": "/api/permission/getnavigationbar,/api/monitor/getids4users,/api/monitor/getaccesslogs,/api/monitor/server,/api/monitor/getactiveusers,/api/monitor/server,"
|
||||
},
|
||||
"SignalR": {
|
||||
"Enabled": false
|
||||
"Enabled": true
|
||||
},
|
||||
"SignalRSendLog": {
|
||||
"Enabled": true
|
||||
},
|
||||
"QuartzNetJob": {
|
||||
"Enabled": true
|
||||
|
@ -285,5 +339,10 @@
|
|||
"FiedValue": "Blog.Core.Api"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Seq": {
|
||||
"Enabled": true,
|
||||
"Address": "http://localhost:5341/",
|
||||
"ApiKey": ""
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user