refactor: 引入管理端 DbContext 禁用租户过滤
This commit is contained in:
@@ -37,7 +37,7 @@ public static class AppServiceCollectionExtensions
|
||||
public static IServiceCollection AddAppInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddDatabaseInfrastructure(configuration);
|
||||
services.AddPostgresDbContext<TakeoutAppDbContext>(DatabaseConstants.AppDataSource);
|
||||
services.AddPostgresDbContext<TakeoutAdminDbContext>(DatabaseConstants.AppDataSource);
|
||||
services.AddPostgresDbContext<TakeoutLogsDbContext>(DatabaseConstants.LogsDataSource);
|
||||
|
||||
services.AddScoped<IMerchantRepository, EfMerchantRepository>();
|
||||
|
||||
@@ -36,7 +36,7 @@ public sealed class AppDataSeeder(
|
||||
}
|
||||
|
||||
using var scope = serviceProvider.CreateScope();
|
||||
var appDbContext = scope.ServiceProvider.GetRequiredService<TakeoutAppDbContext>();
|
||||
var appDbContext = scope.ServiceProvider.GetRequiredService<TakeoutAdminDbContext>();
|
||||
var dictionaryDbContext = scope.ServiceProvider.GetRequiredService<DictionaryDbContext>();
|
||||
|
||||
await EnsurePlatformTenantAsync(appDbContext, cancellationToken);
|
||||
@@ -52,7 +52,7 @@ public sealed class AppDataSeeder(
|
||||
/// <summary>
|
||||
/// 确保默认租户存在。
|
||||
/// </summary>
|
||||
private async Task<long?> EnsureDefaultTenantAsync(TakeoutAppDbContext dbContext, CancellationToken cancellationToken)
|
||||
private async Task<long?> EnsureDefaultTenantAsync(TakeoutAdminDbContext dbContext, CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantOptions = _options.DefaultTenant;
|
||||
if (tenantOptions == null || string.IsNullOrWhiteSpace(tenantOptions.Code) || string.IsNullOrWhiteSpace(tenantOptions.Name))
|
||||
@@ -134,7 +134,7 @@ public sealed class AppDataSeeder(
|
||||
/// <summary>
|
||||
/// 确保平台租户存在。
|
||||
/// </summary>
|
||||
private async Task EnsurePlatformTenantAsync(TakeoutAppDbContext dbContext, CancellationToken cancellationToken)
|
||||
private async Task EnsurePlatformTenantAsync(TakeoutAdminDbContext dbContext, CancellationToken cancellationToken)
|
||||
{
|
||||
var existingTenant = await dbContext.Tenants
|
||||
.IgnoreQueryFilters()
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace TakeoutSaaS.Infrastructure.App.Persistence.Repositories;
|
||||
/// <summary>
|
||||
/// 租户账单仓储实现(EF Core)。
|
||||
/// </summary>
|
||||
public sealed class TenantBillingRepository(TakeoutAppDbContext context) : ITenantBillingRepository
|
||||
public sealed class TenantBillingRepository(TakeoutAdminDbContext context) : ITenantBillingRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<TenantBillingStatement>> SearchAsync(
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace TakeoutSaaS.Infrastructure.App.Persistence.Repositories;
|
||||
/// <summary>
|
||||
/// 租户支付记录仓储实现(EF Core)。
|
||||
/// </summary>
|
||||
public sealed class TenantPaymentRepository(TakeoutAppDbContext context) : ITenantPaymentRepository
|
||||
public sealed class TenantPaymentRepository(TakeoutAdminDbContext context) : ITenantPaymentRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<TenantPayment>> GetByBillingIdAsync(long billingStatementId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
/// <summary>
|
||||
/// 管理端业务主库 DbContext:不启用租户全局过滤,用于跨租户查询与平台级任务。
|
||||
/// </summary>
|
||||
public sealed class TakeoutAdminDbContext(
|
||||
DbContextOptions<TakeoutAdminDbContext> options,
|
||||
ITenantProvider tenantProvider,
|
||||
ICurrentUserAccessor? currentUserAccessor = null,
|
||||
IIdGenerator? idGenerator = null,
|
||||
IHttpContextAccessor? httpContextAccessor = null)
|
||||
: TakeoutAppDbContext(options, tenantProvider, currentUserAccessor, idGenerator, httpContextAccessor)
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置实体映射关系(不启用租户过滤)。
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder">模型构建器。</param>
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
// 1. 构建基础模型(复用实体映射)
|
||||
OnModelCreatingCore(modelBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
/// <summary>
|
||||
/// 业务主库 DbContext。
|
||||
/// </summary>
|
||||
public sealed class TakeoutAppDbContext(
|
||||
DbContextOptions<TakeoutAppDbContext> options,
|
||||
public class TakeoutAppDbContext(
|
||||
DbContextOptions options,
|
||||
ITenantProvider tenantProvider,
|
||||
ICurrentUserAccessor? currentUserAccessor = null,
|
||||
IIdGenerator? idGenerator = null,
|
||||
@@ -382,10 +382,29 @@ public sealed class TakeoutAppDbContext(
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder">模型构建器。</param>
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
// 1. 构建基础模型(软删除/注释 + 实体映射)
|
||||
OnModelCreatingCore(modelBuilder);
|
||||
|
||||
// 2. (空行后) 应用租户过滤
|
||||
ApplyTenantQueryFilters(modelBuilder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 共享模型构建逻辑:软删除/注释 + 全部实体映射(不包含租户过滤)。
|
||||
/// </summary>
|
||||
/// <param name="modelBuilder">模型构建器。</param>
|
||||
protected void OnModelCreatingCore(ModelBuilder modelBuilder)
|
||||
{
|
||||
// 1. 调用基类配置
|
||||
base.OnModelCreating(modelBuilder);
|
||||
// 2. 配置全部实体映射
|
||||
|
||||
// 2. (空行后) 配置全部实体映射
|
||||
ConfigureModel(modelBuilder);
|
||||
}
|
||||
|
||||
internal static void ConfigureModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
ConfigureTenant(modelBuilder.Entity<Tenant>());
|
||||
ConfigureMerchant(modelBuilder.Entity<Merchant>());
|
||||
ConfigureStore(modelBuilder.Entity<Store>());
|
||||
@@ -470,8 +489,6 @@ public sealed class TakeoutAppDbContext(
|
||||
ConfigureMetricDefinition(modelBuilder.Entity<MetricDefinition>());
|
||||
ConfigureMetricSnapshot(modelBuilder.Entity<MetricSnapshot>());
|
||||
ConfigureMetricAlertRule(modelBuilder.Entity<MetricAlertRule>());
|
||||
|
||||
ApplyTenantQueryFilters(modelBuilder);
|
||||
}
|
||||
|
||||
private static void ConfigureTenant(EntityTypeBuilder<Tenant> builder)
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <remarks>
|
||||
/// 初始化仓储。
|
||||
/// </remarks>
|
||||
public sealed class EfDeliveryRepository(TakeoutAppDbContext context) : IDeliveryRepository
|
||||
public sealed class EfDeliveryRepository(TakeoutAdminDbContext context) : IDeliveryRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<DeliveryOrder?> FindByIdAsync(long deliveryOrderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <remarks>
|
||||
/// 提供库存与批次的读写能力。
|
||||
/// </remarks>
|
||||
public sealed class EfInventoryRepository(TakeoutAppDbContext context) : IInventoryRepository
|
||||
public sealed class EfInventoryRepository(TakeoutAdminDbContext context) : IInventoryRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<InventoryItem?> FindByIdAsync(long inventoryItemId, long tenantId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// 商户类目的 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfMerchantCategoryRepository(TakeoutAppDbContext context)
|
||||
public sealed class EfMerchantCategoryRepository(TakeoutAdminDbContext context)
|
||||
: IMerchantCategoryRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <remarks>
|
||||
/// 初始化仓储。
|
||||
/// </remarks>
|
||||
public sealed class EfMerchantRepository(TakeoutAppDbContext context, TakeoutLogsDbContext logsContext) : IMerchantRepository
|
||||
public sealed class EfMerchantRepository(TakeoutAdminDbContext context, TakeoutLogsDbContext logsContext) : IMerchantRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<Merchant?> FindByIdAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <remarks>
|
||||
/// 初始化仓储。
|
||||
/// </remarks>
|
||||
public sealed class EfOrderRepository(TakeoutAppDbContext context) : IOrderRepository
|
||||
public sealed class EfOrderRepository(TakeoutAdminDbContext context) : IOrderRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<Order?> FindByIdAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <remarks>
|
||||
/// 初始化仓储。
|
||||
/// </remarks>
|
||||
public sealed class EfPaymentRepository(TakeoutAppDbContext context) : IPaymentRepository
|
||||
public sealed class EfPaymentRepository(TakeoutAdminDbContext context) : IPaymentRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<PaymentRecord?> FindByIdAsync(long paymentId, long tenantId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <remarks>
|
||||
/// 初始化仓储。
|
||||
/// </remarks>
|
||||
public sealed class EfProductRepository(TakeoutAppDbContext context) : IProductRepository
|
||||
public sealed class EfProductRepository(TakeoutAdminDbContext context) : IProductRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<Product?> FindByIdAsync(long productId, long tenantId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// EF 配额包仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfQuotaPackageRepository(TakeoutAppDbContext context) : IQuotaPackageRepository
|
||||
public sealed class EfQuotaPackageRepository(TakeoutAdminDbContext context) : IQuotaPackageRepository
|
||||
{
|
||||
#region 配额包定义
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// 统计数据仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfStatisticsRepository(TakeoutAppDbContext dbContext) : IStatisticsRepository
|
||||
public sealed class EfStatisticsRepository(TakeoutAdminDbContext dbContext) : IStatisticsRepository
|
||||
{
|
||||
#region 订阅统计
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <remarks>
|
||||
/// 初始化仓储。
|
||||
/// </remarks>
|
||||
public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepository
|
||||
public sealed class EfStoreRepository(TakeoutAdminDbContext context) : IStoreRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<Store?> FindByIdAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// 订阅管理仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfSubscriptionRepository(TakeoutAppDbContext dbContext, TakeoutLogsDbContext logsContext) : ISubscriptionRepository
|
||||
public sealed class EfSubscriptionRepository(TakeoutAdminDbContext dbContext, TakeoutLogsDbContext logsContext) : ISubscriptionRepository
|
||||
{
|
||||
#region 订阅查询
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// EF 公告已读仓储。
|
||||
/// </summary>
|
||||
public sealed class EfTenantAnnouncementReadRepository(TakeoutAppDbContext context) : ITenantAnnouncementReadRepository
|
||||
public sealed class EfTenantAnnouncementReadRepository(TakeoutAdminDbContext context) : ITenantAnnouncementReadRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<IReadOnlyList<TenantAnnouncementRead>> GetByAnnouncementAsync(long tenantId, long announcementId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// EF 租户公告仓储。
|
||||
/// </summary>
|
||||
public sealed class EfTenantAnnouncementRepository(TakeoutAppDbContext context) : ITenantAnnouncementRepository
|
||||
public sealed class EfTenantAnnouncementRepository(TakeoutAdminDbContext context) : ITenantAnnouncementRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<TenantAnnouncement>> SearchAsync(
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// EF 租户通知仓储。
|
||||
/// </summary>
|
||||
public sealed class EfTenantNotificationRepository(TakeoutAppDbContext context) : ITenantNotificationRepository
|
||||
public sealed class EfTenantNotificationRepository(TakeoutAdminDbContext context) : ITenantNotificationRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<IReadOnlyList<TenantNotification>> SearchAsync(
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// 租户套餐仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfTenantPackageRepository(TakeoutAppDbContext context) : ITenantPackageRepository
|
||||
public sealed class EfTenantPackageRepository(TakeoutAdminDbContext context) : ITenantPackageRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<TenantPackage?> FindByIdAsync(long id, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// 租户配额使用历史仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfTenantQuotaUsageHistoryRepository(TakeoutAppDbContext context) : ITenantQuotaUsageHistoryRepository
|
||||
public sealed class EfTenantQuotaUsageHistoryRepository(TakeoutAdminDbContext context) : ITenantQuotaUsageHistoryRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task AddAsync(TenantQuotaUsageHistory history, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// 租户配额使用仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfTenantQuotaUsageRepository(TakeoutAppDbContext context) : ITenantQuotaUsageRepository
|
||||
public sealed class EfTenantQuotaUsageRepository(TakeoutAdminDbContext context) : ITenantQuotaUsageRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<TenantQuotaUsage?> FindAsync(long tenantId, TenantQuotaType quotaType, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
/// <summary>
|
||||
/// 租户聚合的 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfTenantRepository(TakeoutAppDbContext context, TakeoutLogsDbContext logsContext) : ITenantRepository
|
||||
public sealed class EfTenantRepository(TakeoutAdminDbContext context, TakeoutLogsDbContext logsContext) : ITenantRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<Tenant?> FindByIdAsync(long tenantId, CancellationToken cancellationToken = default)
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace TakeoutSaaS.Infrastructure.App.Services;
|
||||
/// 门店定时任务服务实现。
|
||||
/// </summary>
|
||||
public sealed class StoreSchedulerService(
|
||||
TakeoutAppDbContext context,
|
||||
TakeoutAdminDbContext context,
|
||||
ILogger<StoreSchedulerService> logger)
|
||||
: IStoreSchedulerService
|
||||
{
|
||||
|
||||
@@ -68,7 +68,7 @@ public sealed class AutoRenewalService : BackgroundService
|
||||
_logger.LogInformation("开始处理自动续费");
|
||||
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<TakeoutAppDbContext>();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<TakeoutAdminDbContext>();
|
||||
var idGenerator = scope.ServiceProvider.GetRequiredService<IIdGenerator>();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
@@ -68,7 +68,7 @@ public sealed class RenewalReminderService : BackgroundService
|
||||
_logger.LogInformation("开始发送续费提醒");
|
||||
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<TakeoutAppDbContext>();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<TakeoutAdminDbContext>();
|
||||
var idGenerator = scope.ServiceProvider.GetRequiredService<IIdGenerator>();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
@@ -66,7 +66,7 @@ public sealed class SubscriptionExpiryCheckService : BackgroundService
|
||||
_logger.LogInformation("开始执行订阅到期检查");
|
||||
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<TakeoutAppDbContext>();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<TakeoutAdminDbContext>();
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var gracePeriodDays = _options.GracePeriodDays;
|
||||
|
||||
Reference in New Issue
Block a user