🎨 多租户完善

1.完善多租户-多库方案
2.增加租户管理 (实际业务中 也是运维、系统管理员等角色来操作 甚至直接维护数据库而不会开放接口)
This commit is contained in:
Lemon.NoCry 2023-02-18 20:58:43 +08:00
parent 296201998d
commit d85087cbdb
8 changed files with 241 additions and 3 deletions

View File

@ -1247,6 +1247,12 @@
</summary>
<returns></returns>
</member>
<member name="M:Blog.Core.Api.Controllers.Tenant.TenantByDbController.Post(Blog.Core.Model.Models.SubLibraryBusinessTable)">
<summary>
新增数据
</summary>
<returns></returns>
</member>
<member name="T:Blog.Core.Api.Controllers.Tenant.TenantByIdController">
<summary>
多租户-Id方案 测试
@ -1264,6 +1270,44 @@
</summary>
<returns></returns>
</member>
<member name="T:Blog.Core.Api.Controllers.Tenant.TenantManagerController">
<summary>
租户管理
</summary>
</member>
<member name="M:Blog.Core.Api.Controllers.Tenant.TenantManagerController.GetAll">
<summary>
获取全部租户
</summary>
<returns></returns>
</member>
<member name="M:Blog.Core.Api.Controllers.Tenant.TenantManagerController.GetInfo(System.Int64)">
<summary>
获取租户信息
</summary>
<returns></returns>
</member>
<member name="M:Blog.Core.Api.Controllers.Tenant.TenantManagerController.Post(Blog.Core.Model.Models.SysTenant)">
<summary>
新增租户信息 <br/>
此处只做演示,具体要以实际业务为准
</summary>
<returns></returns>
</member>
<member name="M:Blog.Core.Api.Controllers.Tenant.TenantManagerController.Put(Blog.Core.Model.Models.SysTenant)">
<summary>
修改租户信息 <br/>
此处只做演示,具体要以实际业务为准
</summary>
<returns></returns>
</member>
<member name="M:Blog.Core.Api.Controllers.Tenant.TenantManagerController.Delete(System.Int64)">
<summary>
删除租户 <br/>
此处只做演示,具体要以实际业务为准
</summary>
<returns></returns>
</member>
<member name="T:Blog.Core.SwaggerHelper.CustomRouteAttribute">
<summary>
自定义路由 /api/{version}/[controler]/[action]

View File

@ -9,7 +9,7 @@ using Microsoft.AspNetCore.Mvc;
namespace Blog.Core.Api.Controllers.Tenant;
/// <summary>
/// 多租户测试
/// 多租户-多库方案 测试
/// </summary>
[Produces("application/json")]
[Route("api/Tenant/ByDb")]
@ -35,4 +35,16 @@ public class TenantByDbController : BaseApiController
var data = await _services.Query();
return Success(data);
}
/// <summary>
/// 新增数据
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<MessageModel> Post(SubLibraryBusinessTable data)
{
await _services.Db.Insertable(data).ExecuteReturnSnowflakeIdAsync();
return Success();
}
}

View File

@ -0,0 +1,87 @@
using Blog.Core.Controllers;
using Blog.Core.IServices;
using Blog.Core.Model;
using Blog.Core.Model.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Blog.Core.Api.Controllers.Tenant;
/// <summary>
/// 租户管理
/// </summary>
[Produces("application/json")]
[Route("api/TenantManager")]
[Authorize]
public class TenantManagerController : BaseApiController
{
private readonly ITenantService _services;
public TenantManagerController(ITenantService services)
{
_services = services;
}
/// <summary>
/// 获取全部租户
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<MessageModel<List<SysTenant>>> GetAll()
{
var data = await _services.Query();
return Success(data);
}
/// <summary>
/// 获取租户信息
/// </summary>
/// <returns></returns>
[HttpGet("{id}")]
public async Task<MessageModel<SysTenant>> GetInfo(long id)
{
var data = await _services.QueryById(id);
return Success(data);
}
/// <summary>
/// 新增租户信息 <br/>
/// 此处只做演示,具体要以实际业务为准
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<MessageModel> Post(SysTenant tenant)
{
await _services.SaveTenant(tenant);
return Success();
}
/// <summary>
/// 修改租户信息 <br/>
/// 此处只做演示,具体要以实际业务为准
/// </summary>
/// <returns></returns>
[HttpPut]
public async Task<MessageModel> Put(SysTenant tenant)
{
await _services.SaveTenant(tenant);
return Success();
}
/// <summary>
/// 删除租户 <br/>
/// 此处只做演示,具体要以实际业务为准
/// </summary>
/// <returns></returns>
[HttpDelete]
public async Task<MessageModel> Delete(long id)
{
//是否删除租户库?
//要根据实际情况而定
//例如直接删除租户库、备份租户库到xx
await _services.DeleteById(id);
return Success();
}
}

View File

@ -1,4 +1,5 @@
using System;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -106,6 +107,8 @@ namespace Blog.Core.Common.DB
return mutiDBOperate;
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.IO;
using Blog.Core.Model.Models;
using SqlSugar;
@ -6,6 +7,26 @@ namespace Blog.Core.Common.DB;
public static class TenantUtil
{
public static SysTenant DefaultTenantConfig(this SysTenant tenant)
{
tenant.DbType ??= DbType.Sqlite;
//如果没有配置连接
if (tenant.Connection.IsNullOrEmpty())
{
//此处默认配置 Sqlite 地址
//实际业务中 也会有运维、系统管理员等来维护
switch (tenant.DbType.Value)
{
case DbType.Sqlite:
tenant.Connection = $"DataSource={Path.Combine(Environment.CurrentDirectory, tenant.ConfigId)}.db" ;
break;
}
}
return tenant;
}
public static ConnectionConfig GetConnectionConfig(this SysTenant tenant)
{
if (tenant.DbType is null)
@ -13,6 +34,7 @@ public static class TenantUtil
throw new ArgumentException("Tenant DbType Must");
}
return new ConnectionConfig()
{
ConfigId = tenant.ConfigId,

View File

@ -372,7 +372,7 @@ namespace Blog.Core.Common.Seed
return false;
});
if (!seedDataTypes.Any()) return;
foreach (var seedType in seedDataTypes)
{
@ -437,6 +437,7 @@ namespace Blog.Core.Common.Seed
public static async Task InitTenantSeedAsync(ITenant itenant, ConnectionConfig config)
{
itenant.RemoveConnection(config.ConfigId);
itenant.AddConnection(config);
var db = itenant.GetConnectionScope(config.ConfigId);

View File

@ -0,0 +1,12 @@
using System.Threading.Tasks;
using Blog.Core.IServices.BASE;
using Blog.Core.Model.Models;
namespace Blog.Core.IServices;
public interface ITenantService : IBaseServices<SysTenant>
{
public Task SaveTenant(SysTenant tenant);
public Task InitTenantDb(SysTenant tenant);
}

View File

@ -0,0 +1,57 @@
using Blog.Core.Common.DB;
using Blog.Core.Common.Seed;
using Blog.Core.IServices;
using Blog.Core.Model.Models;
using Blog.Core.Repository.UnitOfWorks;
using Blog.Core.Services.BASE;
using System.Threading.Tasks;
namespace Blog.Core.Services;
public class TenantService : BaseServices<SysTenant>, ITenantService
{
private readonly IUnitOfWorkManage _uowManager;
public TenantService(IUnitOfWorkManage uowManage)
{
this._uowManager = uowManage;
}
public async Task SaveTenant(SysTenant tenant)
{
bool initDb = tenant.Id == 0;
using (var uow = _uowManager.CreateUnitOfWork())
{
tenant.DefaultTenantConfig();
if (tenant.Id == 0)
{
await Db.Insertable(tenant).ExecuteReturnSnowflakeIdAsync();
}
else
{
var oldTenant = await QueryById(tenant.Id);
if (oldTenant.Connection != tenant.Connection)
{
initDb = true;
}
await Db.Updateable(tenant).ExecuteCommandAsync();
}
uow.Commit();
}
if (initDb)
{
await InitTenantDb(tenant);
}
}
public async Task InitTenantDb(SysTenant tenant)
{
await DBSeed.InitTenantSeedAsync(Db.AsTenant(), tenant.GetConnectionConfig());
}
}