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.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 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();
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)
{
base.OnModelCreating(modelBuilder);
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());
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).HasMaxLength(256);
builder.Property(x => x.Remarks).HasMaxLength(512);
builder.HasIndex(x => x.Code).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 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 builder)
{
builder.ToTable("reservations");
builder.HasKey(x => x.Id);
builder.Property(x => x.ReservationNo).HasMaxLength(32).IsRequired();
builder.Property(x => x.CustomerName).HasMaxLength(64).IsRequired();
builder.Property(x => x.CustomerPhone).HasMaxLength(32).IsRequired();
builder.Property(x => x.TablePreference).HasMaxLength(64);
builder.Property(x => x.Remark).HasMaxLength(512);
builder.Property(x => x.CheckInCode).HasMaxLength(32);
builder.HasIndex(x => new { x.TenantId, x.StoreId });
builder.HasIndex(x => new { x.TenantId, x.ReservationNo }).IsUnique();
}
private static void ConfigureQueueTicket(EntityTypeBuilder builder)
{
builder.ToTable("queue_tickets");
builder.HasKey(x => x.Id);
builder.Property(x => x.TicketNumber).HasMaxLength(32).IsRequired();
builder.Property(x => x.Remark).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.StoreId });
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.TicketNumber }).IsUnique();
}
private static void ConfigureDelivery(EntityTypeBuilder builder)
{
builder.ToTable("delivery_orders");
builder.HasKey(x => x.Id);
builder.Property(x => x.ProviderOrderId).HasMaxLength(64);
builder.Property(x => x.DeliveryFee).HasPrecision(18, 2);
builder.Property(x => x.CourierName).HasMaxLength(64);
builder.Property(x => x.CourierPhone).HasMaxLength(32);
builder.Property(x => x.FailureReason).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.OrderId }).IsUnique();
}
private static void ConfigureTenantPackage(EntityTypeBuilder builder)
{
builder.ToTable("tenant_packages");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
builder.Property(x => x.Description).HasMaxLength(512);
builder.Property(x => x.FeaturePoliciesJson).HasColumnType("text");
}
private static void ConfigureTenantSubscription(EntityTypeBuilder