feat: 扩展领域模型与配置

This commit is contained in:
贺爱泽
2025-12-01 13:26:05 +08:00
parent a08804658b
commit 5ddad07658
148 changed files with 8519 additions and 2 deletions

View File

@@ -0,0 +1,221 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using TakeoutSaaS.Domain.Deliveries.Entities;
using TakeoutSaaS.Domain.Merchants.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.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Infrastructure.App.Persistence;
/// <summary>
/// 业务主库 DbContext。
/// </summary>
public sealed class TakeoutAppDbContext(
DbContextOptions<TakeoutAppDbContext> options,
ITenantProvider tenantProvider,
ICurrentUserAccessor? currentUserAccessor = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor)
{
public DbSet<Tenant> Tenants => Set<Tenant>();
public DbSet<Merchant> Merchants => Set<Merchant>();
public DbSet<Store> Stores => Set<Store>();
public DbSet<ProductCategory> ProductCategories => Set<ProductCategory>();
public DbSet<Product> Products => Set<Product>();
public DbSet<Order> Orders => Set<Order>();
public DbSet<OrderItem> OrderItems => Set<OrderItem>();
public DbSet<PaymentRecord> PaymentRecords => Set<PaymentRecord>();
public DbSet<Reservation> Reservations => Set<Reservation>();
public DbSet<QueueTicket> QueueTickets => Set<QueueTicket>();
public DbSet<DeliveryOrder> DeliveryOrders => Set<DeliveryOrder>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
ConfigureTenant(modelBuilder.Entity<Tenant>());
ConfigureMerchant(modelBuilder.Entity<Merchant>());
ConfigureStore(modelBuilder.Entity<Store>());
ConfigureProductCategory(modelBuilder.Entity<ProductCategory>());
ConfigureProduct(modelBuilder.Entity<Product>());
ConfigureOrder(modelBuilder.Entity<Order>());
ConfigureOrderItem(modelBuilder.Entity<OrderItem>());
ConfigurePaymentRecord(modelBuilder.Entity<PaymentRecord>());
ConfigureReservation(modelBuilder.Entity<Reservation>());
ConfigureQueueTicket(modelBuilder.Entity<QueueTicket>());
ConfigureDelivery(modelBuilder.Entity<DeliveryOrder>());
ApplyTenantQueryFilters(modelBuilder);
}
private static void ConfigureTenant(EntityTypeBuilder<Tenant> 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 ConfigureMerchant(EntityTypeBuilder<Merchant> 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<Store> 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<ProductCategory> 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<Product> 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<Order> 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<OrderItem> 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<Order>()
.WithMany()
.HasForeignKey(x => x.OrderId)
.OnDelete(DeleteBehavior.Cascade);
}
private static void ConfigurePaymentRecord(EntityTypeBuilder<PaymentRecord> 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<Reservation> 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<QueueTicket> 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<DeliveryOrder> 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();
}
}