using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using TakeoutSaaS.Domain.Analytics.Entities;
using TakeoutSaaS.Domain.Coupons.Entities;
using TakeoutSaaS.Domain.CustomerService.Entities;
using TakeoutSaaS.Domain.Deliveries.Entities;
using TakeoutSaaS.Domain.Distribution.Entities;
using TakeoutSaaS.Domain.Engagement.Entities;
using TakeoutSaaS.Domain.GroupBuying.Entities;
using TakeoutSaaS.Domain.Inventory.Entities;
using TakeoutSaaS.Domain.Membership.Entities;
using TakeoutSaaS.Domain.Merchants.Entities;
using TakeoutSaaS.Domain.Navigation.Entities;
using TakeoutSaaS.Domain.Ordering.Entities;
using TakeoutSaaS.Domain.Orders.Entities;
using TakeoutSaaS.Domain.Payments.Entities;
using TakeoutSaaS.Domain.Products.Entities;
using TakeoutSaaS.Domain.Queues.Entities;
using TakeoutSaaS.Domain.Reservations.Entities;
using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Infrastructure.Common.Persistence;
using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Infrastructure.App.Persistence;
///
/// 业务主库 DbContext。
///
public sealed class TakeoutAppDbContext(
DbContextOptions options,
ITenantProvider tenantProvider,
ICurrentUserAccessor? currentUserAccessor = null,
IIdGenerator? idGenerator = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
{
///
/// 租户聚合根。
///
public DbSet Tenants => Set();
///
/// 租户套餐。
///
public DbSet TenantPackages => Set();
///
/// 租户订阅。
///
public DbSet TenantSubscriptions => Set();
///
/// 租户订阅历史。
///
public DbSet TenantSubscriptionHistories => Set();
///
/// 租户配额使用记录。
///
public DbSet TenantQuotaUsages => Set();
///
/// 租户账单。
///
public DbSet TenantBillingStatements => Set();
///
/// 租户通知。
///
public DbSet TenantNotifications => Set();
///
/// 租户公告。
///
public DbSet TenantAnnouncements => Set();
///
/// 租户公告已读记录。
///
public DbSet TenantAnnouncementReads => Set();
///
/// 租户认证资料。
///
public DbSet TenantVerificationProfiles => Set();
///
/// 租户审计日志。
///
public DbSet TenantAuditLogs => Set();
///
/// 租户审核领取记录。
///
public DbSet TenantReviewClaims => Set();
///
/// 商户实体。
///
public DbSet Merchants => Set();
///
/// 商户资质文件。
///
public DbSet MerchantDocuments => Set();
///
/// 商户合同。
///
public DbSet MerchantContracts => Set();
///
/// 商户员工。
///
public DbSet MerchantStaff => Set();
///
/// 商户审计日志。
///
public DbSet MerchantAuditLogs => Set();
///
/// 商户分类。
///
public DbSet MerchantCategories => Set();
///
/// 门店实体。
///
public DbSet Stores => Set();
///
/// 门店营业时间。
///
public DbSet StoreBusinessHours => Set();
///
/// 门店节假日。
///
public DbSet StoreHolidays => Set();
///
/// 门店配送区域。
///
public DbSet StoreDeliveryZones => Set();
///
/// 门店桌台区域。
///
public DbSet StoreTableAreas => Set();
///
/// 门店桌台。
///
public DbSet StoreTables => Set();
///
/// 门店员工班次。
///
public DbSet StoreEmployeeShifts => Set();
///
/// 自提配置。
///
public DbSet StorePickupSettings => Set();
///
/// 自提时间段。
///
public DbSet StorePickupSlots => Set();
///
/// 商品分类。
///
public DbSet ProductCategories => Set();
///
/// 商品。
///
public DbSet Products => Set();
///
/// 商品属性组。
///
public DbSet ProductAttributeGroups => Set();
///
/// 商品属性项。
///
public DbSet ProductAttributeOptions => Set();
///
/// SKU 实体。
///
public DbSet ProductSkus => Set();
///
/// 加料分组。
///
public DbSet ProductAddonGroups => Set();
///
/// 加料选项。
///
public DbSet ProductAddonOptions => Set();
///
/// 定价规则。
///
public DbSet ProductPricingRules => Set();
///
/// 商品媒体资源。
///
public DbSet ProductMediaAssets => Set();
///
/// 库存项目。
///
public DbSet InventoryItems => Set();
///
/// 库存调整记录。
///
public DbSet InventoryAdjustments => Set();
///
/// 库存批次。
///
public DbSet InventoryBatches => Set();
///
/// 库存锁定记录。
///
public DbSet InventoryLockRecords => Set();
///
/// 购物车。
///
public DbSet ShoppingCarts => Set();
///
/// 购物车明细。
///
public DbSet CartItems => Set();
///
/// 购物车加料。
///
public DbSet CartItemAddons => Set();
///
/// 结账会话。
///
public DbSet CheckoutSessions => Set();
///
/// 订单聚合。
///
public DbSet Orders => Set();
///
/// 订单明细。
///
public DbSet OrderItems => Set();
///
/// 订单状态流转。
///
public DbSet OrderStatusHistories => Set();
///
/// 退款申请。
///
public DbSet RefundRequests => Set();
///
/// 支付记录。
///
public DbSet PaymentRecords => Set();
///
/// 支付退款记录。
///
public DbSet PaymentRefundRecords => Set();
///
/// 预订记录。
///
public DbSet Reservations => Set();
///
/// 排号记录。
///
public DbSet QueueTickets => Set();
///
/// 配送订单。
///
public DbSet DeliveryOrders => Set();
///
/// 配送事件。
///
public DbSet DeliveryEvents => Set();
///
/// 团购订单。
///
public DbSet GroupOrders => Set();
///
/// 团购参与者。
///
public DbSet GroupParticipants => Set();
///
/// 优惠券模板。
///
public DbSet CouponTemplates => Set();
///
/// 优惠券实例。
///
public DbSet Coupons => Set();
///
/// 营销活动。
///
public DbSet PromotionCampaigns => Set();
///
/// 会员档案。
///
public DbSet MemberProfiles => Set();
///
/// 会员等级。
///
public DbSet MemberTiers => Set();
///
/// 积分流水。
///
public DbSet MemberPointLedgers => Set();
///
/// 成长值日志。
///
public DbSet MemberGrowthLogs => Set();
///
/// 会话记录。
///
public DbSet ChatSessions => Set();
///
/// 会话消息。
///
public DbSet ChatMessages => Set();
///
/// 工单记录。
///
public DbSet SupportTickets => Set();
///
/// 工单评论。
///
public DbSet TicketComments => Set();
///
/// 分销合作伙伴。
///
public DbSet AffiliatePartners => Set();
///
/// 分销订单。
///
public DbSet AffiliateOrders => Set();
///
/// 分销结算。
///
public DbSet AffiliatePayouts => Set();
///
/// 打卡活动。
///
public DbSet CheckInCampaigns => Set();
///
/// 打卡记录。
///
public DbSet CheckInRecords => Set();
///
/// 社区帖子。
///
public DbSet CommunityPosts => Set();
///
/// 社区评论。
///
public DbSet CommunityComments => Set();
///
/// 社区互动。
///
public DbSet CommunityReactions => Set();
///
/// 地图位置。
///
public DbSet MapLocations => Set();
///
/// 导航请求。
///
public DbSet NavigationRequests => Set();
///
/// 指标定义。
///
public DbSet MetricDefinitions => Set();
///
/// 指标快照。
///
public DbSet MetricSnapshots => Set();
///
/// 告警规则。
///
public DbSet MetricAlertRules => Set();
///
/// 配置实体映射关系。
///
/// 模型构建器。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 1. 调用基类配置
base.OnModelCreating(modelBuilder);
// 2. 配置全部实体映射
ConfigureTenant(modelBuilder.Entity());
ConfigureMerchant(modelBuilder.Entity());
ConfigureStore(modelBuilder.Entity());
ConfigureTenantPackage(modelBuilder.Entity());
ConfigureTenantSubscription(modelBuilder.Entity());
ConfigureTenantSubscriptionHistory(modelBuilder.Entity());
ConfigureTenantQuotaUsage(modelBuilder.Entity());
ConfigureTenantBilling(modelBuilder.Entity());
ConfigureTenantNotification(modelBuilder.Entity());
ConfigureTenantAnnouncement(modelBuilder.Entity());
ConfigureTenantAnnouncementRead(modelBuilder.Entity());
ConfigureTenantVerificationProfile(modelBuilder.Entity());
ConfigureTenantAuditLog(modelBuilder.Entity());
ConfigureTenantReviewClaim(modelBuilder.Entity());
ConfigureMerchantDocument(modelBuilder.Entity());
ConfigureMerchantContract(modelBuilder.Entity());
ConfigureMerchantStaff(modelBuilder.Entity());
ConfigureMerchantAuditLog(modelBuilder.Entity());
ConfigureMerchantCategory(modelBuilder.Entity());
ConfigureStoreBusinessHour(modelBuilder.Entity());
ConfigureStoreHoliday(modelBuilder.Entity());
ConfigureStoreDeliveryZone(modelBuilder.Entity());
ConfigureStoreTableArea(modelBuilder.Entity());
ConfigureStoreTable(modelBuilder.Entity());
ConfigureStoreEmployeeShift(modelBuilder.Entity());
ConfigureStorePickupSetting(modelBuilder.Entity());
ConfigureStorePickupSlot(modelBuilder.Entity());
ConfigureProductCategory(modelBuilder.Entity());
ConfigureProduct(modelBuilder.Entity());
ConfigureProductAttributeGroup(modelBuilder.Entity());
ConfigureProductAttributeOption(modelBuilder.Entity());
ConfigureProductSku(modelBuilder.Entity());
ConfigureProductAddonGroup(modelBuilder.Entity());
ConfigureProductAddonOption(modelBuilder.Entity());
ConfigureProductPricingRule(modelBuilder.Entity());
ConfigureProductMediaAsset(modelBuilder.Entity());
ConfigureInventoryItem(modelBuilder.Entity());
ConfigureInventoryAdjustment(modelBuilder.Entity());
ConfigureInventoryBatch(modelBuilder.Entity());
ConfigureInventoryLockRecord(modelBuilder.Entity());
ConfigureShoppingCart(modelBuilder.Entity());
ConfigureCartItem(modelBuilder.Entity());
ConfigureCartItemAddon(modelBuilder.Entity());
ConfigureCheckoutSession(modelBuilder.Entity());
ConfigureOrder(modelBuilder.Entity());
ConfigureOrderItem(modelBuilder.Entity());
ConfigureOrderStatusHistory(modelBuilder.Entity());
ConfigureRefundRequest(modelBuilder.Entity());
ConfigurePaymentRecord(modelBuilder.Entity());
ConfigurePaymentRefundRecord(modelBuilder.Entity());
ConfigureReservation(modelBuilder.Entity());
ConfigureQueueTicket(modelBuilder.Entity());
ConfigureDelivery(modelBuilder.Entity());
ConfigureDeliveryEvent(modelBuilder.Entity());
ConfigureGroupOrder(modelBuilder.Entity());
ConfigureGroupParticipant(modelBuilder.Entity());
ConfigureCouponTemplate(modelBuilder.Entity());
ConfigureCoupon(modelBuilder.Entity());
ConfigurePromotionCampaign(modelBuilder.Entity());
ConfigureMemberProfile(modelBuilder.Entity());
ConfigureMemberTier(modelBuilder.Entity());
ConfigureMemberPointLedger(modelBuilder.Entity());
ConfigureMemberGrowthLog(modelBuilder.Entity());
ConfigureChatSession(modelBuilder.Entity());
ConfigureChatMessage(modelBuilder.Entity());
ConfigureSupportTicket(modelBuilder.Entity());
ConfigureTicketComment(modelBuilder.Entity());
ConfigureAffiliatePartner(modelBuilder.Entity());
ConfigureAffiliateOrder(modelBuilder.Entity());
ConfigureAffiliatePayout(modelBuilder.Entity());
ConfigureCheckInCampaign(modelBuilder.Entity());
ConfigureCheckInRecord(modelBuilder.Entity());
ConfigureCommunityPost(modelBuilder.Entity());
ConfigureCommunityComment(modelBuilder.Entity());
ConfigureCommunityReaction(modelBuilder.Entity());
ConfigureMapLocation(modelBuilder.Entity());
ConfigureNavigationRequest(modelBuilder.Entity());
ConfigureMetricDefinition(modelBuilder.Entity());
ConfigureMetricSnapshot(modelBuilder.Entity());
ConfigureMetricAlertRule(modelBuilder.Entity());
ApplyTenantQueryFilters(modelBuilder);
}
private static void ConfigureTenant(EntityTypeBuilder builder)
{
builder.ToTable("tenants");
builder.HasKey(x => x.Id);
builder.Property(x => x.Code).HasMaxLength(64).IsRequired();
builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
builder.Property(x => x.ShortName).HasMaxLength(64);
builder.Property(x => x.ContactName).HasMaxLength(64);
builder.Property(x => x.ContactPhone).HasMaxLength(32);
builder.Property(x => x.ContactEmail).HasMaxLength(128);
builder.Property(x => x.Industry).HasMaxLength(64);
builder.Property(x => x.LogoUrl).HasColumnType("text");
builder.Property(x => x.Remarks).HasMaxLength(512);
builder.HasIndex(x => x.Code).IsUnique();
builder.HasIndex(x => x.ContactPhone).IsUnique();
}
private static void ConfigureTenantVerificationProfile(EntityTypeBuilder builder)
{
builder.ToTable("tenant_verification_profiles");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.BusinessLicenseNumber).HasMaxLength(64);
builder.Property(x => x.BusinessLicenseUrl).HasMaxLength(512);
builder.Property(x => x.LegalPersonName).HasMaxLength(64);
builder.Property(x => x.LegalPersonIdNumber).HasMaxLength(32);
builder.Property(x => x.LegalPersonIdFrontUrl).HasMaxLength(512);
builder.Property(x => x.LegalPersonIdBackUrl).HasMaxLength(512);
builder.Property(x => x.BankAccountName).HasMaxLength(128);
builder.Property(x => x.BankAccountNumber).HasMaxLength(64);
builder.Property(x => x.BankName).HasMaxLength(128);
builder.Property(x => x.ReviewRemarks).HasMaxLength(512);
builder.Property(x => x.ReviewedByName).HasMaxLength(64);
builder.HasIndex(x => x.TenantId).IsUnique();
}
private static void ConfigureTenantAuditLog(EntityTypeBuilder builder)
{
builder.ToTable("tenant_audit_logs");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
builder.Property(x => x.Description).HasMaxLength(1024);
builder.Property(x => x.OperatorName).HasMaxLength(64);
builder.HasIndex(x => x.TenantId);
}
private static void ConfigureTenantReviewClaim(EntityTypeBuilder builder)
{
builder.ToTable("tenant_review_claims");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.ClaimedBy).IsRequired();
builder.Property(x => x.ClaimedByName).HasMaxLength(64).IsRequired();
builder.Property(x => x.ClaimedAt).IsRequired();
builder.Property(x => x.ReleasedAt);
builder.HasIndex(x => x.TenantId);
builder.HasIndex(x => x.ClaimedBy);
builder.HasIndex(x => x.TenantId).IsUnique().HasFilter("\"ReleasedAt\" IS NULL AND \"DeletedAt\" IS NULL");
}
private static void ConfigureTenantSubscriptionHistory(EntityTypeBuilder builder)
{
builder.ToTable("tenant_subscription_histories");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantId).IsRequired();
builder.Property(x => x.TenantSubscriptionId).IsRequired();
builder.Property(x => x.Notes).HasMaxLength(512);
builder.Property(x => x.Currency).HasMaxLength(8);
builder.HasIndex(x => new { x.TenantId, x.TenantSubscriptionId });
}
private static void ConfigureMerchant(EntityTypeBuilder builder)
{
builder.ToTable("merchants");
builder.HasKey(x => x.Id);
builder.Property(x => x.BrandName).HasMaxLength(128).IsRequired();
builder.Property(x => x.BrandAlias).HasMaxLength(64);
builder.Property(x => x.LegalPerson).HasMaxLength(64);
builder.Property(x => x.BusinessLicenseNumber).HasMaxLength(64);
builder.Property(x => x.ContactPhone).HasMaxLength(32).IsRequired();
builder.Property(x => x.ContactEmail).HasMaxLength(128);
builder.Property(x => x.Province).HasMaxLength(64);
builder.Property(x => x.City).HasMaxLength(64);
builder.Property(x => x.District).HasMaxLength(64);
builder.Property(x => x.Address).HasMaxLength(256);
builder.Property(x => x.ReviewRemarks).HasMaxLength(512);
builder.HasIndex(x => x.TenantId);
}
private static void ConfigureStore(EntityTypeBuilder builder)
{
builder.ToTable("stores");
builder.HasKey(x => x.Id);
builder.Property(x => x.Code).HasMaxLength(32).IsRequired();
builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
builder.Property(x => x.Phone).HasMaxLength(32);
builder.Property(x => x.ManagerName).HasMaxLength(64);
builder.Property(x => x.Province).HasMaxLength(64);
builder.Property(x => x.City).HasMaxLength(64);
builder.Property(x => x.District).HasMaxLength(64);
builder.Property(x => x.Address).HasMaxLength(256);
builder.Property(x => x.BusinessHours).HasMaxLength(256);
builder.Property(x => x.Announcement).HasMaxLength(512);
builder.Property(x => x.DeliveryRadiusKm).HasPrecision(6, 2);
builder.HasIndex(x => new { x.TenantId, x.MerchantId });
builder.HasIndex(x => new { x.TenantId, x.Code }).IsUnique();
}
private static void ConfigureProductCategory(EntityTypeBuilder builder)
{
builder.ToTable("product_categories");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.Description).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.StoreId });
}
private static void ConfigureProduct(EntityTypeBuilder builder)
{
builder.ToTable("products");
builder.HasKey(x => x.Id);
builder.Property(x => x.SpuCode).HasMaxLength(32).IsRequired();
builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
builder.Property(x => x.Subtitle).HasMaxLength(256);
builder.Property(x => x.Unit).HasMaxLength(16);
builder.Property(x => x.Price).HasPrecision(18, 2);
builder.Property(x => x.OriginalPrice).HasPrecision(18, 2);
builder.Property(x => x.CoverImage).HasMaxLength(256);
builder.Property(x => x.GalleryImages).HasMaxLength(1024);
builder.Property(x => x.Description).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.StoreId });
builder.HasIndex(x => new { x.TenantId, x.SpuCode }).IsUnique();
}
private static void ConfigureOrder(EntityTypeBuilder builder)
{
builder.ToTable("orders");
builder.HasKey(x => x.Id);
builder.Property(x => x.OrderNo).HasMaxLength(32).IsRequired();
builder.Property(x => x.CustomerName).HasMaxLength(64);
builder.Property(x => x.CustomerPhone).HasMaxLength(32);
builder.Property(x => x.TableNo).HasMaxLength(32);
builder.Property(x => x.QueueNumber).HasMaxLength(32);
builder.Property(x => x.CancelReason).HasMaxLength(256);
builder.Property(x => x.Remark).HasMaxLength(512);
builder.Property(x => x.ItemsAmount).HasPrecision(18, 2);
builder.Property(x => x.DiscountAmount).HasPrecision(18, 2);
builder.Property(x => x.PayableAmount).HasPrecision(18, 2);
builder.Property(x => x.PaidAmount).HasPrecision(18, 2);
builder.HasIndex(x => new { x.TenantId, x.OrderNo }).IsUnique();
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.Status });
}
private static void ConfigureOrderItem(EntityTypeBuilder builder)
{
builder.ToTable("order_items");
builder.HasKey(x => x.Id);
builder.Property(x => x.ProductName).HasMaxLength(128).IsRequired();
builder.Property(x => x.SkuName).HasMaxLength(128);
builder.Property(x => x.Unit).HasMaxLength(16);
builder.Property(x => x.UnitPrice).HasPrecision(18, 2);
builder.Property(x => x.DiscountAmount).HasPrecision(18, 2);
builder.Property(x => x.SubTotal).HasPrecision(18, 2);
builder.Property(x => x.AttributesJson).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.OrderId });
builder.HasOne()
.WithMany()
.HasForeignKey(x => x.OrderId)
.OnDelete(DeleteBehavior.Cascade);
}
private static void ConfigurePaymentRecord(EntityTypeBuilder builder)
{
builder.ToTable("payment_records");
builder.HasKey(x => x.Id);
builder.Property(x => x.Amount).HasPrecision(18, 2);
builder.Property(x => x.TradeNo).HasMaxLength(64);
builder.Property(x => x.ChannelTransactionId).HasMaxLength(64);
builder.Property(x => x.Remark).HasMaxLength(256);
builder.Property(x => x.Payload).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.OrderId });
}
private static void ConfigureReservation(EntityTypeBuilder