feat: 补充数据库脚本和配置

This commit is contained in:
贺爱泽
2025-12-01 18:16:49 +08:00
parent 84ac31158c
commit 15fc000cfc
37 changed files with 42829 additions and 448 deletions

View File

@@ -2,18 +2,27 @@
"Database": {
"DataSources": {
"AppDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"IdentityDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"DictionaryDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
@@ -134,7 +143,7 @@
"PrefetchCount": 20
},
"Scheduler": {
"ConnectionString": "Host=120.53.222.17;Port=5432;Database=takeout_saas_hangfire;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"ConnectionString": "Host=120.53.222.17;Port=5432;Database=takeout_hangfire_db;Username=hangfire_user;Password=HangFire112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"WorkerCount": 5,
"DashboardEnabled": false,
"DashboardPath": "/hangfire"

View File

@@ -2,18 +2,27 @@
"Database": {
"DataSources": {
"AppDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"IdentityDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"DictionaryDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
@@ -134,7 +143,7 @@
"PrefetchCount": 20
},
"Scheduler": {
"ConnectionString": "Host=120.53.222.17;Port=5432;Database=takeout_saas_hangfire;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"ConnectionString": "Host=120.53.222.17;Port=5432;Database=takeout_hangfire_db;Username=hangfire_user;Password=HangFire112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"WorkerCount": 5,
"DashboardEnabled": false,
"DashboardPath": "/hangfire"

View File

@@ -2,18 +2,27 @@
"Database": {
"DataSources": {
"AppDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"IdentityDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"DictionaryDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,

View File

@@ -2,18 +2,27 @@
"Database": {
"DataSources": {
"AppDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"IdentityDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"DictionaryDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,

View File

@@ -2,18 +2,27 @@
"Database": {
"DataSources": {
"AppDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"IdentityDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"DictionaryDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,

View File

@@ -2,18 +2,27 @@
"Database": {
"DataSources": {
"AppDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_app;Username=app_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"IdentityDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=MsuMshk112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,
"MaxRetryDelaySeconds": 5
},
"DictionaryDatabase": {
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
"Reads": [
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
],
"CommandTimeoutSeconds": 30,
"MaxRetryCount": 3,

View File

@@ -14,4 +14,9 @@ public static class DatabaseConstants
/// 身份认证库IdentityDatabase
/// </summary>
public const string IdentityDataSource = "IdentityDatabase";
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD>⣨DictionaryDatabase<73><65><EFBFBD><EFBFBD>
/// </summary>
public const string DictionaryDataSource = "DictionaryDatabase";
}

View File

@@ -3,6 +3,8 @@
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
</Project>

View File

@@ -3,6 +3,8 @@
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\TakeoutSaaS.Shared.Abstractions\TakeoutSaaS.Shared.Abstractions.csproj" />

View File

@@ -1,7 +1,17 @@
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;
@@ -25,16 +35,91 @@ public sealed class TakeoutAppDbContext(
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor)
{
public DbSet<Tenant> Tenants => Set<Tenant>();
public DbSet<TenantPackage> TenantPackages => Set<TenantPackage>();
public DbSet<TenantSubscription> TenantSubscriptions => Set<TenantSubscription>();
public DbSet<TenantQuotaUsage> TenantQuotaUsages => Set<TenantQuotaUsage>();
public DbSet<TenantBillingStatement> TenantBillingStatements => Set<TenantBillingStatement>();
public DbSet<TenantNotification> TenantNotifications => Set<TenantNotification>();
public DbSet<Merchant> Merchants => Set<Merchant>();
public DbSet<MerchantDocument> MerchantDocuments => Set<MerchantDocument>();
public DbSet<MerchantContract> MerchantContracts => Set<MerchantContract>();
public DbSet<MerchantStaff> MerchantStaff => Set<MerchantStaff>();
public DbSet<Store> Stores => Set<Store>();
public DbSet<StoreBusinessHour> StoreBusinessHours => Set<StoreBusinessHour>();
public DbSet<StoreHoliday> StoreHolidays => Set<StoreHoliday>();
public DbSet<StoreDeliveryZone> StoreDeliveryZones => Set<StoreDeliveryZone>();
public DbSet<StoreTableArea> StoreTableAreas => Set<StoreTableArea>();
public DbSet<StoreTable> StoreTables => Set<StoreTable>();
public DbSet<StoreEmployeeShift> StoreEmployeeShifts => Set<StoreEmployeeShift>();
public DbSet<ProductCategory> ProductCategories => Set<ProductCategory>();
public DbSet<Product> Products => Set<Product>();
public DbSet<ProductAttributeGroup> ProductAttributeGroups => Set<ProductAttributeGroup>();
public DbSet<ProductAttributeOption> ProductAttributeOptions => Set<ProductAttributeOption>();
public DbSet<ProductSku> ProductSkus => Set<ProductSku>();
public DbSet<ProductAddonGroup> ProductAddonGroups => Set<ProductAddonGroup>();
public DbSet<ProductAddonOption> ProductAddonOptions => Set<ProductAddonOption>();
public DbSet<ProductPricingRule> ProductPricingRules => Set<ProductPricingRule>();
public DbSet<ProductMediaAsset> ProductMediaAssets => Set<ProductMediaAsset>();
public DbSet<InventoryItem> InventoryItems => Set<InventoryItem>();
public DbSet<InventoryAdjustment> InventoryAdjustments => Set<InventoryAdjustment>();
public DbSet<InventoryBatch> InventoryBatches => Set<InventoryBatch>();
public DbSet<ShoppingCart> ShoppingCarts => Set<ShoppingCart>();
public DbSet<CartItem> CartItems => Set<CartItem>();
public DbSet<CartItemAddon> CartItemAddons => Set<CartItemAddon>();
public DbSet<CheckoutSession> CheckoutSessions => Set<CheckoutSession>();
public DbSet<Order> Orders => Set<Order>();
public DbSet<OrderItem> OrderItems => Set<OrderItem>();
public DbSet<OrderStatusHistory> OrderStatusHistories => Set<OrderStatusHistory>();
public DbSet<RefundRequest> RefundRequests => Set<RefundRequest>();
public DbSet<PaymentRecord> PaymentRecords => Set<PaymentRecord>();
public DbSet<PaymentRefundRecord> PaymentRefundRecords => Set<PaymentRefundRecord>();
public DbSet<Reservation> Reservations => Set<Reservation>();
public DbSet<QueueTicket> QueueTickets => Set<QueueTicket>();
public DbSet<DeliveryOrder> DeliveryOrders => Set<DeliveryOrder>();
public DbSet<DeliveryEvent> DeliveryEvents => Set<DeliveryEvent>();
public DbSet<GroupOrder> GroupOrders => Set<GroupOrder>();
public DbSet<GroupParticipant> GroupParticipants => Set<GroupParticipant>();
public DbSet<CouponTemplate> CouponTemplates => Set<CouponTemplate>();
public DbSet<Coupon> Coupons => Set<Coupon>();
public DbSet<PromotionCampaign> PromotionCampaigns => Set<PromotionCampaign>();
public DbSet<MemberProfile> MemberProfiles => Set<MemberProfile>();
public DbSet<MemberTier> MemberTiers => Set<MemberTier>();
public DbSet<MemberPointLedger> MemberPointLedgers => Set<MemberPointLedger>();
public DbSet<MemberGrowthLog> MemberGrowthLogs => Set<MemberGrowthLog>();
public DbSet<ChatSession> ChatSessions => Set<ChatSession>();
public DbSet<ChatMessage> ChatMessages => Set<ChatMessage>();
public DbSet<SupportTicket> SupportTickets => Set<SupportTicket>();
public DbSet<TicketComment> TicketComments => Set<TicketComment>();
public DbSet<AffiliatePartner> AffiliatePartners => Set<AffiliatePartner>();
public DbSet<AffiliateOrder> AffiliateOrders => Set<AffiliateOrder>();
public DbSet<AffiliatePayout> AffiliatePayouts => Set<AffiliatePayout>();
public DbSet<CheckInCampaign> CheckInCampaigns => Set<CheckInCampaign>();
public DbSet<CheckInRecord> CheckInRecords => Set<CheckInRecord>();
public DbSet<CommunityPost> CommunityPosts => Set<CommunityPost>();
public DbSet<CommunityComment> CommunityComments => Set<CommunityComment>();
public DbSet<CommunityReaction> CommunityReactions => Set<CommunityReaction>();
public DbSet<MapLocation> MapLocations => Set<MapLocation>();
public DbSet<NavigationRequest> NavigationRequests => Set<NavigationRequest>();
public DbSet<MetricDefinition> MetricDefinitions => Set<MetricDefinition>();
public DbSet<MetricSnapshot> MetricSnapshots => Set<MetricSnapshot>();
public DbSet<MetricAlertRule> MetricAlertRules => Set<MetricAlertRule>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
@@ -43,14 +128,72 @@ public sealed class TakeoutAppDbContext(
ConfigureTenant(modelBuilder.Entity<Tenant>());
ConfigureMerchant(modelBuilder.Entity<Merchant>());
ConfigureStore(modelBuilder.Entity<Store>());
ConfigureTenantPackage(modelBuilder.Entity<TenantPackage>());
ConfigureTenantSubscription(modelBuilder.Entity<TenantSubscription>());
ConfigureTenantQuotaUsage(modelBuilder.Entity<TenantQuotaUsage>());
ConfigureTenantBilling(modelBuilder.Entity<TenantBillingStatement>());
ConfigureTenantNotification(modelBuilder.Entity<TenantNotification>());
ConfigureMerchantDocument(modelBuilder.Entity<MerchantDocument>());
ConfigureMerchantContract(modelBuilder.Entity<MerchantContract>());
ConfigureMerchantStaff(modelBuilder.Entity<MerchantStaff>());
ConfigureStoreBusinessHour(modelBuilder.Entity<StoreBusinessHour>());
ConfigureStoreHoliday(modelBuilder.Entity<StoreHoliday>());
ConfigureStoreDeliveryZone(modelBuilder.Entity<StoreDeliveryZone>());
ConfigureStoreTableArea(modelBuilder.Entity<StoreTableArea>());
ConfigureStoreTable(modelBuilder.Entity<StoreTable>());
ConfigureStoreEmployeeShift(modelBuilder.Entity<StoreEmployeeShift>());
ConfigureProductCategory(modelBuilder.Entity<ProductCategory>());
ConfigureProduct(modelBuilder.Entity<Product>());
ConfigureProductAttributeGroup(modelBuilder.Entity<ProductAttributeGroup>());
ConfigureProductAttributeOption(modelBuilder.Entity<ProductAttributeOption>());
ConfigureProductSku(modelBuilder.Entity<ProductSku>());
ConfigureProductAddonGroup(modelBuilder.Entity<ProductAddonGroup>());
ConfigureProductAddonOption(modelBuilder.Entity<ProductAddonOption>());
ConfigureProductPricingRule(modelBuilder.Entity<ProductPricingRule>());
ConfigureProductMediaAsset(modelBuilder.Entity<ProductMediaAsset>());
ConfigureInventoryItem(modelBuilder.Entity<InventoryItem>());
ConfigureInventoryAdjustment(modelBuilder.Entity<InventoryAdjustment>());
ConfigureInventoryBatch(modelBuilder.Entity<InventoryBatch>());
ConfigureShoppingCart(modelBuilder.Entity<ShoppingCart>());
ConfigureCartItem(modelBuilder.Entity<CartItem>());
ConfigureCartItemAddon(modelBuilder.Entity<CartItemAddon>());
ConfigureCheckoutSession(modelBuilder.Entity<CheckoutSession>());
ConfigureOrder(modelBuilder.Entity<Order>());
ConfigureOrderItem(modelBuilder.Entity<OrderItem>());
ConfigureOrderStatusHistory(modelBuilder.Entity<OrderStatusHistory>());
ConfigureRefundRequest(modelBuilder.Entity<RefundRequest>());
ConfigurePaymentRecord(modelBuilder.Entity<PaymentRecord>());
ConfigurePaymentRefundRecord(modelBuilder.Entity<PaymentRefundRecord>());
ConfigureReservation(modelBuilder.Entity<Reservation>());
ConfigureQueueTicket(modelBuilder.Entity<QueueTicket>());
ConfigureDelivery(modelBuilder.Entity<DeliveryOrder>());
ConfigureDeliveryEvent(modelBuilder.Entity<DeliveryEvent>());
ConfigureGroupOrder(modelBuilder.Entity<GroupOrder>());
ConfigureGroupParticipant(modelBuilder.Entity<GroupParticipant>());
ConfigureCouponTemplate(modelBuilder.Entity<CouponTemplate>());
ConfigureCoupon(modelBuilder.Entity<Coupon>());
ConfigurePromotionCampaign(modelBuilder.Entity<PromotionCampaign>());
ConfigureMemberProfile(modelBuilder.Entity<MemberProfile>());
ConfigureMemberTier(modelBuilder.Entity<MemberTier>());
ConfigureMemberPointLedger(modelBuilder.Entity<MemberPointLedger>());
ConfigureMemberGrowthLog(modelBuilder.Entity<MemberGrowthLog>());
ConfigureChatSession(modelBuilder.Entity<ChatSession>());
ConfigureChatMessage(modelBuilder.Entity<ChatMessage>());
ConfigureSupportTicket(modelBuilder.Entity<SupportTicket>());
ConfigureTicketComment(modelBuilder.Entity<TicketComment>());
ConfigureAffiliatePartner(modelBuilder.Entity<AffiliatePartner>());
ConfigureAffiliateOrder(modelBuilder.Entity<AffiliateOrder>());
ConfigureAffiliatePayout(modelBuilder.Entity<AffiliatePayout>());
ConfigureCheckInCampaign(modelBuilder.Entity<CheckInCampaign>());
ConfigureCheckInRecord(modelBuilder.Entity<CheckInRecord>());
ConfigureCommunityPost(modelBuilder.Entity<CommunityPost>());
ConfigureCommunityComment(modelBuilder.Entity<CommunityComment>());
ConfigureCommunityReaction(modelBuilder.Entity<CommunityReaction>());
ConfigureMapLocation(modelBuilder.Entity<MapLocation>());
ConfigureNavigationRequest(modelBuilder.Entity<NavigationRequest>());
ConfigureMetricDefinition(modelBuilder.Entity<MetricDefinition>());
ConfigureMetricSnapshot(modelBuilder.Entity<MetricSnapshot>());
ConfigureMetricAlertRule(modelBuilder.Entity<MetricAlertRule>());
ApplyTenantQueryFilters(modelBuilder);
}
@@ -218,4 +361,632 @@ public sealed class TakeoutAppDbContext(
builder.Property(x => x.FailureReason).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.OrderId }).IsUnique();
}
private static void ConfigureTenantPackage(EntityTypeBuilder<TenantPackage> 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<TenantSubscription> builder)
{
builder.ToTable("tenant_subscriptions");
builder.HasKey(x => x.Id);
builder.Property(x => x.TenantPackageId).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.TenantPackageId });
}
private static void ConfigureTenantQuotaUsage(EntityTypeBuilder<TenantQuotaUsage> builder)
{
builder.ToTable("tenant_quota_usages");
builder.HasKey(x => x.Id);
builder.Property(x => x.QuotaType).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.QuotaType }).IsUnique();
}
private static void ConfigureTenantBilling(EntityTypeBuilder<TenantBillingStatement> builder)
{
builder.ToTable("tenant_billing_statements");
builder.HasKey(x => x.Id);
builder.Property(x => x.StatementNo).HasMaxLength(64).IsRequired();
builder.Property(x => x.AmountDue).HasPrecision(18, 2);
builder.Property(x => x.AmountPaid).HasPrecision(18, 2);
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.LineItemsJson).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.StatementNo }).IsUnique();
}
private static void ConfigureTenantNotification(EntityTypeBuilder<TenantNotification> builder)
{
builder.ToTable("tenant_notifications");
builder.HasKey(x => x.Id);
builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
builder.Property(x => x.Message).HasMaxLength(1024).IsRequired();
builder.Property(x => x.Channel).HasConversion<int>();
builder.Property(x => x.Severity).HasConversion<int>();
builder.Property(x => x.MetadataJson).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.Channel, x.SentAt });
}
private static void ConfigureMerchantDocument(EntityTypeBuilder<MerchantDocument> builder)
{
builder.ToTable("merchant_documents");
builder.HasKey(x => x.Id);
builder.Property(x => x.MerchantId).IsRequired();
builder.Property(x => x.DocumentType).HasConversion<int>();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.FileUrl).HasMaxLength(512).IsRequired();
builder.Property(x => x.DocumentNumber).HasMaxLength(64);
builder.HasIndex(x => new { x.TenantId, x.MerchantId, x.DocumentType });
}
private static void ConfigureMerchantContract(EntityTypeBuilder<MerchantContract> builder)
{
builder.ToTable("merchant_contracts");
builder.HasKey(x => x.Id);
builder.Property(x => x.MerchantId).IsRequired();
builder.Property(x => x.ContractNumber).HasMaxLength(64).IsRequired();
builder.Property(x => x.FileUrl).HasMaxLength(512).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.TerminationReason).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.MerchantId, x.ContractNumber }).IsUnique();
}
private static void ConfigureMerchantStaff(EntityTypeBuilder<MerchantStaff> builder)
{
builder.ToTable("merchant_staff");
builder.HasKey(x => x.Id);
builder.Property(x => x.MerchantId).IsRequired();
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.Phone).HasMaxLength(32).IsRequired();
builder.Property(x => x.Email).HasMaxLength(128);
builder.Property(x => x.RoleType).HasConversion<int>();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.PermissionsJson).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.MerchantId, x.Phone });
}
private static void ConfigureStoreBusinessHour(EntityTypeBuilder<StoreBusinessHour> builder)
{
builder.ToTable("store_business_hours");
builder.HasKey(x => x.Id);
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.HourType).HasConversion<int>();
builder.Property(x => x.Notes).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.DayOfWeek });
}
private static void ConfigureStoreHoliday(EntityTypeBuilder<StoreHoliday> builder)
{
builder.ToTable("store_holidays");
builder.HasKey(x => x.Id);
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.Reason).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.Date }).IsUnique();
}
private static void ConfigureStoreDeliveryZone(EntityTypeBuilder<StoreDeliveryZone> builder)
{
builder.ToTable("store_delivery_zones");
builder.HasKey(x => x.Id);
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.ZoneName).HasMaxLength(64).IsRequired();
builder.Property(x => x.PolygonGeoJson).HasColumnType("text").IsRequired();
builder.Property(x => x.MinimumOrderAmount).HasPrecision(18, 2);
builder.Property(x => x.DeliveryFee).HasPrecision(18, 2);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.ZoneName });
}
private static void ConfigureStoreTableArea(EntityTypeBuilder<StoreTableArea> builder)
{
builder.ToTable("store_table_areas");
builder.HasKey(x => x.Id);
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.Description).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.Name }).IsUnique();
}
private static void ConfigureStoreTable(EntityTypeBuilder<StoreTable> builder)
{
builder.ToTable("store_tables");
builder.HasKey(x => x.Id);
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.TableCode).HasMaxLength(32).IsRequired();
builder.Property(x => x.Tags).HasMaxLength(128);
builder.Property(x => x.QrCodeUrl).HasMaxLength(512);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.TableCode }).IsUnique();
}
private static void ConfigureStoreEmployeeShift(EntityTypeBuilder<StoreEmployeeShift> builder)
{
builder.ToTable("store_employee_shifts");
builder.HasKey(x => x.Id);
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.StaffId).IsRequired();
builder.Property(x => x.RoleType).HasConversion<int>();
builder.Property(x => x.Notes).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.ShiftDate, x.StaffId }).IsUnique();
}
private static void ConfigureProductAttributeGroup(EntityTypeBuilder<ProductAttributeGroup> builder)
{
builder.ToTable("product_attribute_groups");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.SelectionType).HasConversion<int>();
builder.Property(x => x.StoreId);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.Name });
}
private static void ConfigureProductAttributeOption(EntityTypeBuilder<ProductAttributeOption> builder)
{
builder.ToTable("product_attribute_options");
builder.HasKey(x => x.Id);
builder.Property(x => x.AttributeGroupId).IsRequired();
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.ExtraPrice).HasPrecision(18, 2);
builder.HasIndex(x => new { x.TenantId, x.AttributeGroupId, x.Name }).IsUnique();
}
private static void ConfigureProductSku(EntityTypeBuilder<ProductSku> builder)
{
builder.ToTable("product_skus");
builder.HasKey(x => x.Id);
builder.Property(x => x.ProductId).IsRequired();
builder.Property(x => x.SkuCode).HasMaxLength(32).IsRequired();
builder.Property(x => x.Barcode).HasMaxLength(64);
builder.Property(x => x.Price).HasPrecision(18, 2);
builder.Property(x => x.OriginalPrice).HasPrecision(18, 2);
builder.Property(x => x.Weight).HasPrecision(10, 3);
builder.Property(x => x.AttributesJson).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.SkuCode }).IsUnique();
}
private static void ConfigureProductAddonGroup(EntityTypeBuilder<ProductAddonGroup> builder)
{
builder.ToTable("product_addon_groups");
builder.HasKey(x => x.Id);
builder.Property(x => x.ProductId).IsRequired();
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.SelectionType).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.ProductId, x.Name });
}
private static void ConfigureProductAddonOption(EntityTypeBuilder<ProductAddonOption> builder)
{
builder.ToTable("product_addon_options");
builder.HasKey(x => x.Id);
builder.Property(x => x.AddonGroupId).IsRequired();
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.ExtraPrice).HasPrecision(18, 2);
}
private static void ConfigureProductPricingRule(EntityTypeBuilder<ProductPricingRule> builder)
{
builder.ToTable("product_pricing_rules");
builder.HasKey(x => x.Id);
builder.Property(x => x.ProductId).IsRequired();
builder.Property(x => x.RuleType).HasConversion<int>();
builder.Property(x => x.ConditionsJson).HasColumnType("text").IsRequired();
builder.Property(x => x.Price).HasPrecision(18, 2);
builder.Property(x => x.WeekdaysJson).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.ProductId, x.RuleType });
}
private static void ConfigureProductMediaAsset(EntityTypeBuilder<ProductMediaAsset> builder)
{
builder.ToTable("product_media_assets");
builder.HasKey(x => x.Id);
builder.Property(x => x.ProductId).IsRequired();
builder.Property(x => x.MediaType).HasConversion<int>();
builder.Property(x => x.Url).HasMaxLength(512).IsRequired();
builder.Property(x => x.Caption).HasMaxLength(256);
}
private static void ConfigureInventoryItem(EntityTypeBuilder<InventoryItem> builder)
{
builder.ToTable("inventory_items");
builder.HasKey(x => x.Id);
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.ProductSkuId).IsRequired();
builder.Property(x => x.BatchNumber).HasMaxLength(64);
builder.Property(x => x.Location).HasMaxLength(64);
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.ProductSkuId, x.BatchNumber });
}
private static void ConfigureInventoryAdjustment(EntityTypeBuilder<InventoryAdjustment> builder)
{
builder.ToTable("inventory_adjustments");
builder.HasKey(x => x.Id);
builder.Property(x => x.InventoryItemId).IsRequired();
builder.Property(x => x.AdjustmentType).HasConversion<int>();
builder.Property(x => x.Reason).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.InventoryItemId, x.OccurredAt });
}
private static void ConfigureInventoryBatch(EntityTypeBuilder<InventoryBatch> builder)
{
builder.ToTable("inventory_batches");
builder.HasKey(x => x.Id);
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.ProductSkuId).IsRequired();
builder.Property(x => x.BatchNumber).HasMaxLength(64).IsRequired();
builder.HasIndex(x => new { x.TenantId, x.StoreId, x.ProductSkuId, x.BatchNumber }).IsUnique();
}
private static void ConfigureShoppingCart(EntityTypeBuilder<ShoppingCart> builder)
{
builder.ToTable("shopping_carts");
builder.HasKey(x => x.Id);
builder.Property(x => x.UserId).IsRequired();
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.TableContext).HasMaxLength(64);
builder.Property(x => x.DeliveryPreference).HasMaxLength(32);
builder.HasIndex(x => new { x.TenantId, x.UserId, x.StoreId }).IsUnique();
}
private static void ConfigureCartItem(EntityTypeBuilder<CartItem> builder)
{
builder.ToTable("cart_items");
builder.HasKey(x => x.Id);
builder.Property(x => x.ShoppingCartId).IsRequired();
builder.Property(x => x.ProductId).IsRequired();
builder.Property(x => x.ProductName).HasMaxLength(128).IsRequired();
builder.Property(x => x.UnitPrice).HasPrecision(18, 2);
builder.Property(x => x.Remark).HasMaxLength(256);
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.AttributesJson).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.ShoppingCartId });
}
private static void ConfigureCartItemAddon(EntityTypeBuilder<CartItemAddon> builder)
{
builder.ToTable("cart_item_addons");
builder.HasKey(x => x.Id);
builder.Property(x => x.CartItemId).IsRequired();
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.ExtraPrice).HasPrecision(18, 2);
}
private static void ConfigureCheckoutSession(EntityTypeBuilder<CheckoutSession> builder)
{
builder.ToTable("checkout_sessions");
builder.HasKey(x => x.Id);
builder.Property(x => x.UserId).IsRequired();
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.SessionToken).HasMaxLength(64).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.ValidationResultJson).HasColumnType("text").IsRequired();
builder.HasIndex(x => new { x.TenantId, x.SessionToken }).IsUnique();
}
private static void ConfigureOrderStatusHistory(EntityTypeBuilder<OrderStatusHistory> builder)
{
builder.ToTable("order_status_histories");
builder.HasKey(x => x.Id);
builder.Property(x => x.OrderId).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.Notes).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.OrderId, x.OccurredAt });
}
private static void ConfigureRefundRequest(EntityTypeBuilder<RefundRequest> builder)
{
builder.ToTable("refund_requests");
builder.HasKey(x => x.Id);
builder.Property(x => x.OrderId).IsRequired();
builder.Property(x => x.RefundNo).HasMaxLength(32).IsRequired();
builder.Property(x => x.Amount).HasPrecision(18, 2);
builder.Property(x => x.Reason).HasMaxLength(256).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.ReviewNotes).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.RefundNo }).IsUnique();
}
private static void ConfigurePaymentRefundRecord(EntityTypeBuilder<PaymentRefundRecord> builder)
{
builder.ToTable("payment_refund_records");
builder.HasKey(x => x.Id);
builder.Property(x => x.PaymentRecordId).IsRequired();
builder.Property(x => x.OrderId).IsRequired();
builder.Property(x => x.Amount).HasPrecision(18, 2);
builder.Property(x => x.ChannelRefundId).HasMaxLength(64);
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.Payload).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.PaymentRecordId });
}
private static void ConfigureDeliveryEvent(EntityTypeBuilder<DeliveryEvent> builder)
{
builder.ToTable("delivery_events");
builder.HasKey(x => x.Id);
builder.Property(x => x.DeliveryOrderId).IsRequired();
builder.Property(x => x.EventType).HasConversion<int>();
builder.Property(x => x.Message).HasMaxLength(256);
builder.Property(x => x.Payload).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.DeliveryOrderId, x.EventType });
}
private static void ConfigureGroupOrder(EntityTypeBuilder<GroupOrder> builder)
{
builder.ToTable("group_orders");
builder.HasKey(x => x.Id);
builder.Property(x => x.GroupOrderNo).HasMaxLength(32).IsRequired();
builder.Property(x => x.GroupPrice).HasPrecision(18, 2);
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.GroupOrderNo }).IsUnique();
}
private static void ConfigureGroupParticipant(EntityTypeBuilder<GroupParticipant> builder)
{
builder.ToTable("group_participants");
builder.HasKey(x => x.Id);
builder.Property(x => x.GroupOrderId).IsRequired();
builder.Property(x => x.OrderId).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.GroupOrderId, x.UserId }).IsUnique();
}
private static void ConfigureCouponTemplate(EntityTypeBuilder<CouponTemplate> builder)
{
builder.ToTable("coupon_templates");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
builder.Property(x => x.CouponType).HasConversion<int>();
builder.Property(x => x.Description).HasMaxLength(512);
builder.Property(x => x.TotalQuantity);
builder.Property(x => x.StoreScopeJson).HasColumnType("text");
builder.Property(x => x.ProductScopeJson).HasColumnType("text");
builder.Property(x => x.ChannelsJson).HasColumnType("text");
builder.Property(x => x.Status).HasConversion<int>();
}
private static void ConfigureCoupon(EntityTypeBuilder<Coupon> builder)
{
builder.ToTable("coupons");
builder.HasKey(x => x.Id);
builder.Property(x => x.CouponTemplateId).IsRequired();
builder.Property(x => x.Code).HasMaxLength(32).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.Code }).IsUnique();
}
private static void ConfigurePromotionCampaign(EntityTypeBuilder<PromotionCampaign> builder)
{
builder.ToTable("promotion_campaigns");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
builder.Property(x => x.PromotionType).HasConversion<int>();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.RulesJson).HasColumnType("text").IsRequired();
builder.Property(x => x.AudienceDescription).HasMaxLength(512);
builder.Property(x => x.BannerUrl).HasMaxLength(512);
}
private static void ConfigureMemberProfile(EntityTypeBuilder<MemberProfile> builder)
{
builder.ToTable("member_profiles");
builder.HasKey(x => x.Id);
builder.Property(x => x.Mobile).HasMaxLength(32).IsRequired();
builder.Property(x => x.Nickname).HasMaxLength(64);
builder.Property(x => x.AvatarUrl).HasMaxLength(256);
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.Mobile }).IsUnique();
}
private static void ConfigureMemberTier(EntityTypeBuilder<MemberTier> builder)
{
builder.ToTable("member_tiers");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
builder.Property(x => x.BenefitsJson).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.Name }).IsUnique();
}
private static void ConfigureMemberPointLedger(EntityTypeBuilder<MemberPointLedger> builder)
{
builder.ToTable("member_point_ledgers");
builder.HasKey(x => x.Id);
builder.Property(x => x.MemberId).IsRequired();
builder.Property(x => x.Reason).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.MemberId, x.OccurredAt });
}
private static void ConfigureMemberGrowthLog(EntityTypeBuilder<MemberGrowthLog> builder)
{
builder.ToTable("member_growth_logs");
builder.HasKey(x => x.Id);
builder.Property(x => x.MemberId).IsRequired();
builder.Property(x => x.Notes).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.MemberId, x.OccurredAt });
}
private static void ConfigureChatSession(EntityTypeBuilder<ChatSession> builder)
{
builder.ToTable("chat_sessions");
builder.HasKey(x => x.Id);
builder.Property(x => x.SessionCode).HasMaxLength(64).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.SessionCode }).IsUnique();
}
private static void ConfigureChatMessage(EntityTypeBuilder<ChatMessage> builder)
{
builder.ToTable("chat_messages");
builder.HasKey(x => x.Id);
builder.Property(x => x.ChatSessionId).IsRequired();
builder.Property(x => x.SenderType).HasConversion<int>();
builder.Property(x => x.ContentType).HasMaxLength(64).IsRequired();
builder.Property(x => x.Content).HasMaxLength(1024).IsRequired();
builder.HasIndex(x => new { x.TenantId, x.ChatSessionId, x.CreatedAt });
}
private static void ConfigureSupportTicket(EntityTypeBuilder<SupportTicket> builder)
{
builder.ToTable("support_tickets");
builder.HasKey(x => x.Id);
builder.Property(x => x.TicketNo).HasMaxLength(32).IsRequired();
builder.Property(x => x.Subject).HasMaxLength(128).IsRequired();
builder.Property(x => x.Description).HasColumnType("text").IsRequired();
builder.Property(x => x.Priority).HasConversion<int>();
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.TicketNo }).IsUnique();
}
private static void ConfigureTicketComment(EntityTypeBuilder<TicketComment> builder)
{
builder.ToTable("ticket_comments");
builder.HasKey(x => x.Id);
builder.Property(x => x.SupportTicketId).IsRequired();
builder.Property(x => x.Content).HasMaxLength(1024).IsRequired();
builder.Property(x => x.AttachmentsJson).HasColumnType("text");
builder.HasIndex(x => new { x.TenantId, x.SupportTicketId });
}
private static void ConfigureAffiliatePartner(EntityTypeBuilder<AffiliatePartner> builder)
{
builder.ToTable("affiliate_partners");
builder.HasKey(x => x.Id);
builder.Property(x => x.DisplayName).HasMaxLength(64).IsRequired();
builder.Property(x => x.Phone).HasMaxLength(32);
builder.Property(x => x.ChannelType).HasConversion<int>();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.Remarks).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.DisplayName });
}
private static void ConfigureAffiliateOrder(EntityTypeBuilder<AffiliateOrder> builder)
{
builder.ToTable("affiliate_orders");
builder.HasKey(x => x.Id);
builder.Property(x => x.AffiliatePartnerId).IsRequired();
builder.Property(x => x.OrderId).IsRequired();
builder.Property(x => x.OrderAmount).HasPrecision(18, 2);
builder.Property(x => x.EstimatedCommission).HasPrecision(18, 2);
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.AffiliatePartnerId, x.OrderId }).IsUnique();
}
private static void ConfigureAffiliatePayout(EntityTypeBuilder<AffiliatePayout> builder)
{
builder.ToTable("affiliate_payouts");
builder.HasKey(x => x.Id);
builder.Property(x => x.AffiliatePartnerId).IsRequired();
builder.Property(x => x.Period).HasMaxLength(32).IsRequired();
builder.Property(x => x.Amount).HasPrecision(18, 2);
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.Remarks).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.AffiliatePartnerId, x.Period }).IsUnique();
}
private static void ConfigureCheckInCampaign(EntityTypeBuilder<CheckInCampaign> builder)
{
builder.ToTable("checkin_campaigns");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
builder.Property(x => x.Description).HasMaxLength(512);
builder.Property(x => x.RewardsJson).HasColumnType("text").IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.Name });
}
private static void ConfigureCheckInRecord(EntityTypeBuilder<CheckInRecord> builder)
{
builder.ToTable("checkin_records");
builder.HasKey(x => x.Id);
builder.Property(x => x.CheckInCampaignId).IsRequired();
builder.Property(x => x.UserId).IsRequired();
builder.Property(x => x.RewardJson).HasColumnType("text").IsRequired();
builder.HasIndex(x => new { x.TenantId, x.CheckInCampaignId, x.UserId, x.CheckInDate }).IsUnique();
}
private static void ConfigureCommunityPost(EntityTypeBuilder<CommunityPost> builder)
{
builder.ToTable("community_posts");
builder.HasKey(x => x.Id);
builder.Property(x => x.AuthorUserId).IsRequired();
builder.Property(x => x.Title).HasMaxLength(128);
builder.Property(x => x.Content).HasColumnType("text").IsRequired();
builder.Property(x => x.MediaJson).HasColumnType("text");
builder.Property(x => x.Status).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.AuthorUserId, x.CreatedAt });
}
private static void ConfigureCommunityComment(EntityTypeBuilder<CommunityComment> builder)
{
builder.ToTable("community_comments");
builder.HasKey(x => x.Id);
builder.Property(x => x.PostId).IsRequired();
builder.Property(x => x.Content).HasMaxLength(512).IsRequired();
builder.HasIndex(x => new { x.TenantId, x.PostId, x.CreatedAt });
}
private static void ConfigureCommunityReaction(EntityTypeBuilder<CommunityReaction> builder)
{
builder.ToTable("community_reactions");
builder.HasKey(x => x.Id);
builder.Property(x => x.PostId).IsRequired();
builder.Property(x => x.ReactionType).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.PostId, x.UserId }).IsUnique();
}
private static void ConfigureMapLocation(EntityTypeBuilder<MapLocation> builder)
{
builder.ToTable("map_locations");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
builder.Property(x => x.Address).HasMaxLength(256).IsRequired();
builder.Property(x => x.Landmark).HasMaxLength(128);
builder.HasIndex(x => new { x.TenantId, x.StoreId });
}
private static void ConfigureNavigationRequest(EntityTypeBuilder<NavigationRequest> builder)
{
builder.ToTable("navigation_requests");
builder.HasKey(x => x.Id);
builder.Property(x => x.UserId).IsRequired();
builder.Property(x => x.StoreId).IsRequired();
builder.Property(x => x.Channel).HasConversion<int>();
builder.Property(x => x.TargetApp).HasConversion<int>();
builder.HasIndex(x => new { x.TenantId, x.UserId, x.StoreId, x.RequestedAt });
}
private static void ConfigureMetricDefinition(EntityTypeBuilder<MetricDefinition> builder)
{
builder.ToTable("metric_definitions");
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.Description).HasMaxLength(512);
builder.Property(x => x.DimensionsJson).HasColumnType("text");
builder.Property(x => x.DefaultAggregation).HasMaxLength(32).IsRequired();
builder.HasIndex(x => new { x.TenantId, x.Code }).IsUnique();
}
private static void ConfigureMetricSnapshot(EntityTypeBuilder<MetricSnapshot> builder)
{
builder.ToTable("metric_snapshots");
builder.HasKey(x => x.Id);
builder.Property(x => x.MetricDefinitionId).IsRequired();
builder.Property(x => x.DimensionKey).HasMaxLength(256).IsRequired();
builder.Property(x => x.Value).HasPrecision(18, 4);
builder.HasIndex(x => new { x.TenantId, x.MetricDefinitionId, x.DimensionKey, x.WindowStart, x.WindowEnd }).IsUnique();
}
private static void ConfigureMetricAlertRule(EntityTypeBuilder<MetricAlertRule> builder)
{
builder.ToTable("metric_alert_rules");
builder.HasKey(x => x.Id);
builder.Property(x => x.MetricDefinitionId).IsRequired();
builder.Property(x => x.ConditionJson).HasColumnType("text").IsRequired();
builder.Property(x => x.Severity).HasConversion<int>();
builder.Property(x => x.NotificationChannels).HasMaxLength(256);
builder.HasIndex(x => new { x.TenantId, x.MetricDefinitionId, x.Severity });
}
}

View File

@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Infrastructure.Common.Persistence.DesignTime;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
@@ -12,7 +13,7 @@ internal sealed class TakeoutAppDesignTimeDbContextFactory
: DesignTimeDbContextFactoryBase<TakeoutAppDbContext>
{
public TakeoutAppDesignTimeDbContextFactory()
: base("TAKEOUTSAAS_APP_CONNECTION", "takeout_saas_app")
: base(DatabaseConstants.AppDataSource, "TAKEOUTSAAS_APP_CONNECTION")
{
}

View File

@@ -21,6 +21,7 @@ public abstract class AppDbContext(DbContextOptions options, ICurrentUserAccesso
{
base.OnModelCreating(modelBuilder);
ApplySoftDeleteQueryFilters(modelBuilder);
modelBuilder.ApplyXmlComments();
}
/// <summary>

View File

@@ -1,25 +1,33 @@
using System;
using System.IO;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using TakeoutSaaS.Infrastructure.Common.Persistence;
using Microsoft.Extensions.Configuration;
using TakeoutSaaS.Infrastructure.Common.Options;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Infrastructure.Common.Persistence.DesignTime;
/// <summary>
/// EF Core 设计时 DbContext 工厂基类,提供统一的连接串与依赖替身
/// EF Core 设计时 DbContext 工厂基类,统一读取 appsettings 中的数据库配置
/// </summary>
internal abstract class DesignTimeDbContextFactoryBase<TContext> : IDesignTimeDbContextFactory<TContext>
where TContext : TenantAwareDbContext
{
private readonly string _connectionStringEnvVar;
private readonly string _defaultDatabase;
private readonly string _dataSourceName;
private readonly string? _connectionStringEnvVar;
protected DesignTimeDbContextFactoryBase(string connectionStringEnvVar, string defaultDatabase)
protected DesignTimeDbContextFactoryBase(string dataSourceName, string? connectionStringEnvVar = null)
{
if (string.IsNullOrWhiteSpace(dataSourceName))
{
throw new ArgumentException("数据源名称不能为空。", nameof(dataSourceName));
}
_dataSourceName = dataSourceName;
_connectionStringEnvVar = connectionStringEnvVar;
_defaultDatabase = defaultDatabase;
}
public TContext CreateDbContext(string[] args)
@@ -46,15 +54,91 @@ internal abstract class DesignTimeDbContextFactoryBase<TContext> : IDesignTimeDb
private string ResolveConnectionString()
{
var env = Environment.GetEnvironmentVariable(_connectionStringEnvVar);
if (!string.IsNullOrWhiteSpace(env))
if (!string.IsNullOrWhiteSpace(_connectionStringEnvVar))
{
return env;
var envValue = Environment.GetEnvironmentVariable(_connectionStringEnvVar);
if (!string.IsNullOrWhiteSpace(envValue))
{
return envValue;
}
}
return $"Host=localhost;Port=5432;Database={_defaultDatabase};Username=postgres;Password=postgres";
var configuration = BuildConfiguration();
var writeConnection = configuration[$"{DatabaseOptions.SectionName}:DataSources:{_dataSourceName}:Write"];
if (string.IsNullOrWhiteSpace(writeConnection))
{
throw new InvalidOperationException(
$"未在配置中找到数据源 '{_dataSourceName}' 的 Write 连接字符串,请检查 appsettings 或设置 {_connectionStringEnvVar ?? ""} 环境变量。");
}
return writeConnection;
}
private static IConfigurationRoot BuildConfiguration()
{
var basePath = ResolveConfigurationDirectory();
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development";
return new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: false)
.AddEnvironmentVariables()
.Build();
}
private static string ResolveConfigurationDirectory()
{
var explicitDir = Environment.GetEnvironmentVariable("TAKEOUTSAAS_APPSETTINGS_DIR");
if (!string.IsNullOrWhiteSpace(explicitDir) && Directory.Exists(explicitDir))
{
return explicitDir;
}
var currentDir = Directory.GetCurrentDirectory();
var solutionRoot = LocateSolutionRoot(currentDir);
var candidateDirs = new[]
{
currentDir,
solutionRoot,
solutionRoot is null ? null : Path.Combine(solutionRoot, "src", "Api", "TakeoutSaaS.AdminApi"),
solutionRoot is null ? null : Path.Combine(solutionRoot, "src", "Api", "TakeoutSaaS.UserApi"),
solutionRoot is null ? null : Path.Combine(solutionRoot, "src", "Api", "TakeoutSaaS.MiniApi")
}.Where(dir => !string.IsNullOrWhiteSpace(dir));
foreach (var dir in candidateDirs)
{
if (dir != null && Directory.Exists(dir) && HasAppSettings(dir))
{
return dir;
}
}
throw new InvalidOperationException(
"未找到 appsettings 配置文件,请设置 TAKEOUTSAAS_APPSETTINGS_DIR 环境变量指向包含 appsettings*.json 的目录。");
}
private static string? LocateSolutionRoot(string currentPath)
{
var directoryInfo = new DirectoryInfo(currentPath);
while (directoryInfo != null)
{
if (File.Exists(Path.Combine(directoryInfo.FullName, "TakeoutSaaS.sln")))
{
return directoryInfo.FullName;
}
directoryInfo = directoryInfo.Parent;
}
return null;
}
private static bool HasAppSettings(string directory) =>
File.Exists(Path.Combine(directory, "appsettings.json")) ||
Directory.GetFiles(directory, "appsettings.*.json").Length > 0;
private sealed class DesignTimeTenantProvider : ITenantProvider
{
public Guid GetCurrentTenantId() => Guid.Empty;

View File

@@ -0,0 +1,136 @@
using System.Collections.Concurrent;
using System.Reflection;
using System.Xml.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
namespace TakeoutSaaS.Infrastructure.Common.Persistence;
/// <summary>
/// Applies XML documentation summaries to EF Core entities/columns as comments.
/// </summary>
internal static class ModelBuilderCommentExtensions
{
public static void ApplyXmlComments(this ModelBuilder modelBuilder)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
ApplyEntityComment(entityType);
}
}
private static void ApplyEntityComment(IMutableEntityType entityType)
{
var clrType = entityType.ClrType;
if (clrType == null)
{
return;
}
if (XmlDocCommentProvider.TryGetSummary(clrType, out var typeComment))
{
entityType.SetComment(typeComment);
}
foreach (var property in entityType.GetProperties())
{
var propertyInfo = property.PropertyInfo;
if (propertyInfo == null)
{
continue;
}
if (XmlDocCommentProvider.TryGetSummary(propertyInfo, out var propertyComment))
{
property.SetComment(propertyComment);
}
}
}
private static class XmlDocCommentProvider
{
private static readonly ConcurrentDictionary<Assembly, IReadOnlyDictionary<string, string>> Cache = new();
public static bool TryGetSummary(MemberInfo member, out string? summary)
{
summary = null;
var assembly = member switch
{
Type type => type.Assembly,
_ => member.DeclaringType?.Assembly
};
if (assembly == null)
{
return false;
}
var map = Cache.GetOrAdd(assembly, LoadComments);
if (map.Count == 0)
{
return false;
}
var key = GetMemberKey(member);
if (key == null || !map.TryGetValue(key, out var text))
{
return false;
}
summary = text;
return true;
}
private static IReadOnlyDictionary<string, string> LoadComments(Assembly assembly)
{
var dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
var xmlPath = Path.ChangeExtension(assembly.Location, ".xml");
if (string.IsNullOrWhiteSpace(xmlPath) || !File.Exists(xmlPath))
{
return dictionary;
}
var document = XDocument.Load(xmlPath);
foreach (var member in document.Descendants("member"))
{
var name = member.Attribute("name")?.Value;
if (string.IsNullOrWhiteSpace(name))
{
continue;
}
var summary = member.Element("summary")?.Value;
if (string.IsNullOrWhiteSpace(summary))
{
continue;
}
var normalized = Normalize(summary);
if (!string.IsNullOrWhiteSpace(normalized))
{
dictionary[name] = normalized;
}
}
return dictionary;
}
private static string? GetMemberKey(MemberInfo member) =>
member switch
{
Type type => $"T:{GetFullName(type)}",
PropertyInfo property => $"P:{GetFullName(property.DeclaringType!)}.{property.Name}",
FieldInfo field => $"F:{GetFullName(field.DeclaringType!)}.{field.Name}",
_ => null
};
private static string GetFullName(Type type) =>
(type.FullName ?? type.Name).Replace('+', '.');
private static string Normalize(string text)
{
var chars = text.Replace('\r', ' ').Replace('\n', ' ').Replace('\t', ' ');
return string.Join(' ', chars.Split(' ', StringSplitOptions.RemoveEmptyEntries));
}
}
}

View File

@@ -28,7 +28,7 @@ public static class DictionaryServiceCollectionExtensions
public static IServiceCollection AddDictionaryInfrastructure(this IServiceCollection services, IConfiguration configuration)
{
services.AddDatabaseInfrastructure(configuration);
services.AddPostgresDbContext<DictionaryDbContext>(DatabaseConstants.AppDataSource);
services.AddPostgresDbContext<DictionaryDbContext>(DatabaseConstants.DictionaryDataSource);
services.AddScoped<IDictionaryRepository, EfDictionaryRepository>();
services.AddScoped<IDictionaryCache, DistributedDictionaryCache>();

View File

@@ -0,0 +1,206 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
#nullable disable
namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
{
[DbContext(typeof(DictionaryDbContext))]
[Migration("20251201094456_AddEntityComments")]
partial class AddEntityComments
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryGroup", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasComment("实体唯一标识。");
b.Property<string>("Code")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasComment("分组编码(唯一)。");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone")
.HasComment("创建时间UTC。");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uuid")
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("timestamp with time zone")
.HasComment("软删除时间UTC未删除时为 null。");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uuid")
.HasComment("删除人用户标识(软删除),未删除时为 null。");
b.Property<string>("Description")
.HasMaxLength(512)
.HasColumnType("character varying(512)")
.HasComment("描述信息。");
b.Property<bool>("IsEnabled")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(true)
.HasComment("是否启用。");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)")
.HasComment("分组名称。");
b.Property<int>("Scope")
.HasColumnType("integer")
.HasComment("分组作用域:系统/业务。");
b.Property<Guid>("TenantId")
.HasColumnType("uuid")
.HasComment("所属租户 ID。");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone")
.HasComment("最近一次更新时间UTC从未更新时为 null。");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uuid")
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
b.HasKey("Id");
b.HasIndex("TenantId");
b.HasIndex("TenantId", "Code")
.IsUnique();
b.ToTable("dictionary_groups", null, t =>
{
t.HasComment("参数字典分组(系统参数、业务参数)。");
});
});
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasComment("实体唯一标识。");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone")
.HasComment("创建时间UTC。");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uuid")
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("timestamp with time zone")
.HasComment("软删除时间UTC未删除时为 null。");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uuid")
.HasComment("删除人用户标识(软删除),未删除时为 null。");
b.Property<string>("Description")
.HasMaxLength(512)
.HasColumnType("character varying(512)")
.HasComment("描述信息。");
b.Property<Guid>("GroupId")
.HasColumnType("uuid")
.HasComment("关联分组 ID。");
b.Property<bool>("IsDefault")
.HasColumnType("boolean")
.HasComment("是否默认项。");
b.Property<bool>("IsEnabled")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(true)
.HasComment("是否启用。");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasComment("字典项键。");
b.Property<int>("SortOrder")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(100)
.HasComment("排序值,越小越靠前。");
b.Property<Guid>("TenantId")
.HasColumnType("uuid")
.HasComment("所属租户 ID。");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone")
.HasComment("最近一次更新时间UTC从未更新时为 null。");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uuid")
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasComment("字典项值。");
b.HasKey("Id");
b.HasIndex("TenantId");
b.HasIndex("GroupId", "Key")
.IsUnique();
b.ToTable("dictionary_items", null, t =>
{
t.HasComment("参数字典项。");
});
});
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryItem", b =>
{
b.HasOne("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryGroup", "Group")
.WithMany("Items")
.HasForeignKey("GroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Group");
});
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryGroup", b =>
{
b.Navigation("Items");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,599 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
{
/// <inheritdoc />
public partial class AddEntityComments : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterTable(
name: "dictionary_items",
comment: "参数字典项。");
migrationBuilder.AlterTable(
name: "dictionary_groups",
comment: "参数字典分组(系统参数、业务参数)。");
migrationBuilder.AlterColumn<string>(
name: "Value",
table: "dictionary_items",
type: "character varying(256)",
maxLength: 256,
nullable: false,
comment: "字典项值。",
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256);
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedBy",
table: "dictionary_items",
type: "uuid",
nullable: true,
comment: "最后更新人用户标识,匿名或系统操作时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "dictionary_items",
type: "timestamp with time zone",
nullable: true,
comment: "最近一次更新时间UTC从未更新时为 null。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "TenantId",
table: "dictionary_items",
type: "uuid",
nullable: false,
comment: "所属租户 ID。",
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<int>(
name: "SortOrder",
table: "dictionary_items",
type: "integer",
nullable: false,
defaultValue: 100,
comment: "排序值,越小越靠前。",
oldClrType: typeof(int),
oldType: "integer",
oldDefaultValue: 100);
migrationBuilder.AlterColumn<string>(
name: "Key",
table: "dictionary_items",
type: "character varying(64)",
maxLength: 64,
nullable: false,
comment: "字典项键。",
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64);
migrationBuilder.AlterColumn<bool>(
name: "IsEnabled",
table: "dictionary_items",
type: "boolean",
nullable: false,
defaultValue: true,
comment: "是否启用。",
oldClrType: typeof(bool),
oldType: "boolean",
oldDefaultValue: true);
migrationBuilder.AlterColumn<bool>(
name: "IsDefault",
table: "dictionary_items",
type: "boolean",
nullable: false,
comment: "是否默认项。",
oldClrType: typeof(bool),
oldType: "boolean");
migrationBuilder.AlterColumn<Guid>(
name: "GroupId",
table: "dictionary_items",
type: "uuid",
nullable: false,
comment: "关联分组 ID。",
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "dictionary_items",
type: "character varying(512)",
maxLength: 512,
nullable: true,
comment: "描述信息。",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "DeletedBy",
table: "dictionary_items",
type: "uuid",
nullable: true,
comment: "删除人用户标识(软删除),未删除时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "DeletedAt",
table: "dictionary_items",
type: "timestamp with time zone",
nullable: true,
comment: "软删除时间UTC未删除时为 null。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "CreatedBy",
table: "dictionary_items",
type: "uuid",
nullable: true,
comment: "创建人用户标识,匿名或系统操作时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "CreatedAt",
table: "dictionary_items",
type: "timestamp with time zone",
nullable: false,
comment: "创建时间UTC。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<Guid>(
name: "Id",
table: "dictionary_items",
type: "uuid",
nullable: false,
comment: "实体唯一标识。",
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedBy",
table: "dictionary_groups",
type: "uuid",
nullable: true,
comment: "最后更新人用户标识,匿名或系统操作时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "dictionary_groups",
type: "timestamp with time zone",
nullable: true,
comment: "最近一次更新时间UTC从未更新时为 null。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "TenantId",
table: "dictionary_groups",
type: "uuid",
nullable: false,
comment: "所属租户 ID。",
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<int>(
name: "Scope",
table: "dictionary_groups",
type: "integer",
nullable: false,
comment: "分组作用域:系统/业务。",
oldClrType: typeof(int),
oldType: "integer");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "dictionary_groups",
type: "character varying(128)",
maxLength: 128,
nullable: false,
comment: "分组名称。",
oldClrType: typeof(string),
oldType: "character varying(128)",
oldMaxLength: 128);
migrationBuilder.AlterColumn<bool>(
name: "IsEnabled",
table: "dictionary_groups",
type: "boolean",
nullable: false,
defaultValue: true,
comment: "是否启用。",
oldClrType: typeof(bool),
oldType: "boolean",
oldDefaultValue: true);
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "dictionary_groups",
type: "character varying(512)",
maxLength: 512,
nullable: true,
comment: "描述信息。",
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "DeletedBy",
table: "dictionary_groups",
type: "uuid",
nullable: true,
comment: "删除人用户标识(软删除),未删除时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "DeletedAt",
table: "dictionary_groups",
type: "timestamp with time zone",
nullable: true,
comment: "软删除时间UTC未删除时为 null。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "CreatedBy",
table: "dictionary_groups",
type: "uuid",
nullable: true,
comment: "创建人用户标识,匿名或系统操作时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "CreatedAt",
table: "dictionary_groups",
type: "timestamp with time zone",
nullable: false,
comment: "创建时间UTC。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<string>(
name: "Code",
table: "dictionary_groups",
type: "character varying(64)",
maxLength: 64,
nullable: false,
comment: "分组编码(唯一)。",
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64);
migrationBuilder.AlterColumn<Guid>(
name: "Id",
table: "dictionary_groups",
type: "uuid",
nullable: false,
comment: "实体唯一标识。",
oldClrType: typeof(Guid),
oldType: "uuid");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterTable(
name: "dictionary_items",
oldComment: "参数字典项。");
migrationBuilder.AlterTable(
name: "dictionary_groups",
oldComment: "参数字典分组(系统参数、业务参数)。");
migrationBuilder.AlterColumn<string>(
name: "Value",
table: "dictionary_items",
type: "character varying(256)",
maxLength: 256,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256,
oldComment: "字典项值。");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedBy",
table: "dictionary_items",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "最后更新人用户标识,匿名或系统操作时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "dictionary_items",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true,
oldComment: "最近一次更新时间UTC从未更新时为 null。");
migrationBuilder.AlterColumn<Guid>(
name: "TenantId",
table: "dictionary_items",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldComment: "所属租户 ID。");
migrationBuilder.AlterColumn<int>(
name: "SortOrder",
table: "dictionary_items",
type: "integer",
nullable: false,
defaultValue: 100,
oldClrType: typeof(int),
oldType: "integer",
oldDefaultValue: 100,
oldComment: "排序值,越小越靠前。");
migrationBuilder.AlterColumn<string>(
name: "Key",
table: "dictionary_items",
type: "character varying(64)",
maxLength: 64,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64,
oldComment: "字典项键。");
migrationBuilder.AlterColumn<bool>(
name: "IsEnabled",
table: "dictionary_items",
type: "boolean",
nullable: false,
defaultValue: true,
oldClrType: typeof(bool),
oldType: "boolean",
oldDefaultValue: true,
oldComment: "是否启用。");
migrationBuilder.AlterColumn<bool>(
name: "IsDefault",
table: "dictionary_items",
type: "boolean",
nullable: false,
oldClrType: typeof(bool),
oldType: "boolean",
oldComment: "是否默认项。");
migrationBuilder.AlterColumn<Guid>(
name: "GroupId",
table: "dictionary_items",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldComment: "关联分组 ID。");
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "dictionary_items",
type: "character varying(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true,
oldComment: "描述信息。");
migrationBuilder.AlterColumn<Guid>(
name: "DeletedBy",
table: "dictionary_items",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "删除人用户标识(软删除),未删除时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "DeletedAt",
table: "dictionary_items",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true,
oldComment: "软删除时间UTC未删除时为 null。");
migrationBuilder.AlterColumn<Guid>(
name: "CreatedBy",
table: "dictionary_items",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "创建人用户标识,匿名或系统操作时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "CreatedAt",
table: "dictionary_items",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldComment: "创建时间UTC。");
migrationBuilder.AlterColumn<Guid>(
name: "Id",
table: "dictionary_items",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldComment: "实体唯一标识。");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedBy",
table: "dictionary_groups",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "最后更新人用户标识,匿名或系统操作时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "dictionary_groups",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true,
oldComment: "最近一次更新时间UTC从未更新时为 null。");
migrationBuilder.AlterColumn<Guid>(
name: "TenantId",
table: "dictionary_groups",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldComment: "所属租户 ID。");
migrationBuilder.AlterColumn<int>(
name: "Scope",
table: "dictionary_groups",
type: "integer",
nullable: false,
oldClrType: typeof(int),
oldType: "integer",
oldComment: "分组作用域:系统/业务。");
migrationBuilder.AlterColumn<string>(
name: "Name",
table: "dictionary_groups",
type: "character varying(128)",
maxLength: 128,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(128)",
oldMaxLength: 128,
oldComment: "分组名称。");
migrationBuilder.AlterColumn<bool>(
name: "IsEnabled",
table: "dictionary_groups",
type: "boolean",
nullable: false,
defaultValue: true,
oldClrType: typeof(bool),
oldType: "boolean",
oldDefaultValue: true,
oldComment: "是否启用。");
migrationBuilder.AlterColumn<string>(
name: "Description",
table: "dictionary_groups",
type: "character varying(512)",
maxLength: 512,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(512)",
oldMaxLength: 512,
oldNullable: true,
oldComment: "描述信息。");
migrationBuilder.AlterColumn<Guid>(
name: "DeletedBy",
table: "dictionary_groups",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "删除人用户标识(软删除),未删除时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "DeletedAt",
table: "dictionary_groups",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true,
oldComment: "软删除时间UTC未删除时为 null。");
migrationBuilder.AlterColumn<Guid>(
name: "CreatedBy",
table: "dictionary_groups",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "创建人用户标识,匿名或系统操作时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "CreatedAt",
table: "dictionary_groups",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldComment: "创建时间UTC。");
migrationBuilder.AlterColumn<string>(
name: "Code",
table: "dictionary_groups",
type: "character varying(64)",
maxLength: 64,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64,
oldComment: "分组编码(唯一)。");
migrationBuilder.AlterColumn<Guid>(
name: "Id",
table: "dictionary_groups",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldComment: "实体唯一标识。");
}
}
}

View File

@@ -26,50 +26,63 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("实体唯一标识。");
b.Property<string>("Code")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
.HasColumnType("character varying(64)")
.HasComment("分组编码(唯一)。");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("创建时间UTC。");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("软删除时间UTC未删除时为 null。");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("删除人用户标识(软删除),未删除时为 null。");
b.Property<string>("Description")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
.HasColumnType("character varying(512)")
.HasComment("描述信息。");
b.Property<bool>("IsEnabled")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(true);
.HasDefaultValue(true)
.HasComment("是否启用。");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
.HasColumnType("character varying(128)")
.HasComment("分组名称。");
b.Property<int>("Scope")
.HasColumnType("integer");
.HasColumnType("integer")
.HasComment("分组作用域:系统/业务。");
b.Property<Guid>("TenantId")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("所属租户 ID。");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("最近一次更新时间UTC从未更新时为 null。");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
b.HasKey("Id");
@@ -78,65 +91,83 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
b.HasIndex("TenantId", "Code")
.IsUnique();
b.ToTable("dictionary_groups", (string)null);
b.ToTable("dictionary_groups", null, t =>
{
t.HasComment("参数字典分组(系统参数、业务参数)。");
});
});
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryItem", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("实体唯一标识。");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("创建时间UTC。");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("软删除时间UTC未删除时为 null。");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("删除人用户标识(软删除),未删除时为 null。");
b.Property<string>("Description")
.HasMaxLength(512)
.HasColumnType("character varying(512)");
.HasColumnType("character varying(512)")
.HasComment("描述信息。");
b.Property<Guid>("GroupId")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("关联分组 ID。");
b.Property<bool>("IsDefault")
.HasColumnType("boolean");
.HasColumnType("boolean")
.HasComment("是否默认项。");
b.Property<bool>("IsEnabled")
.ValueGeneratedOnAdd()
.HasColumnType("boolean")
.HasDefaultValue(true);
.HasDefaultValue(true)
.HasComment("是否启用。");
b.Property<string>("Key")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
.HasColumnType("character varying(64)")
.HasComment("字典项键。");
b.Property<int>("SortOrder")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasDefaultValue(100);
.HasDefaultValue(100)
.HasComment("排序值,越小越靠前。");
b.Property<Guid>("TenantId")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("所属租户 ID。");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("最近一次更新时间UTC从未更新时为 null。");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
b.Property<string>("Value")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)");
.HasColumnType("character varying(256)")
.HasComment("字典项值。");
b.HasKey("Id");
@@ -145,7 +176,10 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
b.HasIndex("GroupId", "Key")
.IsUnique();
b.ToTable("dictionary_items", (string)null);
b.ToTable("dictionary_items", null, t =>
{
t.HasComment("参数字典项。");
});
});
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryItem", b =>

View File

@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Infrastructure.Common.Persistence.DesignTime;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
@@ -12,7 +13,7 @@ internal sealed class DictionaryDesignTimeDbContextFactory
: DesignTimeDbContextFactoryBase<DictionaryDbContext>
{
public DictionaryDesignTimeDbContextFactory()
: base("TAKEOUTSAAS_APP_CONNECTION", "takeout_saas_app")
: base(DatabaseConstants.DictionaryDataSource, "TAKEOUTSAAS_DICTIONARY_CONNECTION")
{
}

View File

@@ -0,0 +1,185 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using TakeoutSaaS.Infrastructure.Identity.Persistence;
#nullable disable
namespace TakeoutSaaS.Infrastructure.Identity.Migrations
{
[DbContext(typeof(IdentityDbContext))]
[Migration("20251201094410_AddEntityComments")]
partial class AddEntityComments
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "10.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.IdentityUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasComment("实体唯一标识。");
b.Property<string>("Account")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasComment("登录账号。");
b.Property<string>("Avatar")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasComment("头像地址。");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone")
.HasComment("创建时间UTC。");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uuid")
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("timestamp with time zone")
.HasComment("软删除时间UTC未删除时为 null。");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uuid")
.HasComment("删除人用户标识(软删除),未删除时为 null。");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasComment("展示名称。");
b.Property<Guid?>("MerchantId")
.HasColumnType("uuid")
.HasComment("所属商户(平台管理员为空)。");
b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasComment("密码哈希。");
b.Property<string>("Permissions")
.IsRequired()
.HasColumnType("text")
.HasComment("权限集合。");
b.Property<string>("Roles")
.IsRequired()
.HasColumnType("text")
.HasComment("角色集合。");
b.Property<Guid>("TenantId")
.HasColumnType("uuid")
.HasComment("所属租户 ID。");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone")
.HasComment("最近一次更新时间UTC从未更新时为 null。");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uuid")
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
b.HasKey("Id");
b.HasIndex("TenantId");
b.HasIndex("TenantId", "Account")
.IsUnique();
b.ToTable("identity_users", null, t =>
{
t.HasComment("管理后台账户实体(平台管理员、租户管理员或商户员工)。");
});
});
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.MiniUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid")
.HasComment("实体唯一标识。");
b.Property<string>("Avatar")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasComment("头像地址。");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone")
.HasComment("创建时间UTC。");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uuid")
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("timestamp with time zone")
.HasComment("软删除时间UTC未删除时为 null。");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uuid")
.HasComment("删除人用户标识(软删除),未删除时为 null。");
b.Property<string>("Nickname")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)")
.HasComment("昵称。");
b.Property<string>("OpenId")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)")
.HasComment("微信 OpenId。");
b.Property<Guid>("TenantId")
.HasColumnType("uuid")
.HasComment("所属租户 ID。");
b.Property<string>("UnionId")
.HasMaxLength(128)
.HasColumnType("character varying(128)")
.HasComment("微信 UnionId可能为空。");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone")
.HasComment("最近一次更新时间UTC从未更新时为 null。");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uuid")
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
b.HasKey("Id");
b.HasIndex("TenantId");
b.HasIndex("TenantId", "OpenId")
.IsUnique();
b.ToTable("mini_users", null, t =>
{
t.HasComment("小程序用户实体。");
});
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,581 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TakeoutSaaS.Infrastructure.Identity.Migrations
{
/// <inheritdoc />
public partial class AddEntityComments : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterTable(
name: "mini_users",
comment: "小程序用户实体。");
migrationBuilder.AlterTable(
name: "identity_users",
comment: "管理后台账户实体(平台管理员、租户管理员或商户员工)。");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedBy",
table: "mini_users",
type: "uuid",
nullable: true,
comment: "最后更新人用户标识,匿名或系统操作时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "mini_users",
type: "timestamp with time zone",
nullable: true,
comment: "最近一次更新时间UTC从未更新时为 null。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "UnionId",
table: "mini_users",
type: "character varying(128)",
maxLength: 128,
nullable: true,
comment: "微信 UnionId可能为空。",
oldClrType: typeof(string),
oldType: "character varying(128)",
oldMaxLength: 128,
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "TenantId",
table: "mini_users",
type: "uuid",
nullable: false,
comment: "所属租户 ID。",
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<string>(
name: "OpenId",
table: "mini_users",
type: "character varying(128)",
maxLength: 128,
nullable: false,
comment: "微信 OpenId。",
oldClrType: typeof(string),
oldType: "character varying(128)",
oldMaxLength: 128);
migrationBuilder.AlterColumn<string>(
name: "Nickname",
table: "mini_users",
type: "character varying(64)",
maxLength: 64,
nullable: false,
comment: "昵称。",
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64);
migrationBuilder.AlterColumn<Guid>(
name: "DeletedBy",
table: "mini_users",
type: "uuid",
nullable: true,
comment: "删除人用户标识(软删除),未删除时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "DeletedAt",
table: "mini_users",
type: "timestamp with time zone",
nullable: true,
comment: "软删除时间UTC未删除时为 null。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "CreatedBy",
table: "mini_users",
type: "uuid",
nullable: true,
comment: "创建人用户标识,匿名或系统操作时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "CreatedAt",
table: "mini_users",
type: "timestamp with time zone",
nullable: false,
comment: "创建时间UTC。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<string>(
name: "Avatar",
table: "mini_users",
type: "character varying(256)",
maxLength: 256,
nullable: true,
comment: "头像地址。",
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "Id",
table: "mini_users",
type: "uuid",
nullable: false,
comment: "实体唯一标识。",
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedBy",
table: "identity_users",
type: "uuid",
nullable: true,
comment: "最后更新人用户标识,匿名或系统操作时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "identity_users",
type: "timestamp with time zone",
nullable: true,
comment: "最近一次更新时间UTC从未更新时为 null。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "TenantId",
table: "identity_users",
type: "uuid",
nullable: false,
comment: "所属租户 ID。",
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<string>(
name: "Roles",
table: "identity_users",
type: "text",
nullable: false,
comment: "角色集合。",
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AlterColumn<string>(
name: "Permissions",
table: "identity_users",
type: "text",
nullable: false,
comment: "权限集合。",
oldClrType: typeof(string),
oldType: "text");
migrationBuilder.AlterColumn<string>(
name: "PasswordHash",
table: "identity_users",
type: "character varying(256)",
maxLength: 256,
nullable: false,
comment: "密码哈希。",
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256);
migrationBuilder.AlterColumn<Guid>(
name: "MerchantId",
table: "identity_users",
type: "uuid",
nullable: true,
comment: "所属商户(平台管理员为空)。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "DisplayName",
table: "identity_users",
type: "character varying(64)",
maxLength: 64,
nullable: false,
comment: "展示名称。",
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64);
migrationBuilder.AlterColumn<Guid>(
name: "DeletedBy",
table: "identity_users",
type: "uuid",
nullable: true,
comment: "删除人用户标识(软删除),未删除时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "DeletedAt",
table: "identity_users",
type: "timestamp with time zone",
nullable: true,
comment: "软删除时间UTC未删除时为 null。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "CreatedBy",
table: "identity_users",
type: "uuid",
nullable: true,
comment: "创建人用户标识,匿名或系统操作时为 null。",
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<DateTime>(
name: "CreatedAt",
table: "identity_users",
type: "timestamp with time zone",
nullable: false,
comment: "创建时间UTC。",
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone");
migrationBuilder.AlterColumn<string>(
name: "Avatar",
table: "identity_users",
type: "character varying(256)",
maxLength: 256,
nullable: true,
comment: "头像地址。",
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256,
oldNullable: true);
migrationBuilder.AlterColumn<string>(
name: "Account",
table: "identity_users",
type: "character varying(64)",
maxLength: 64,
nullable: false,
comment: "登录账号。",
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64);
migrationBuilder.AlterColumn<Guid>(
name: "Id",
table: "identity_users",
type: "uuid",
nullable: false,
comment: "实体唯一标识。",
oldClrType: typeof(Guid),
oldType: "uuid");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterTable(
name: "mini_users",
oldComment: "小程序用户实体。");
migrationBuilder.AlterTable(
name: "identity_users",
oldComment: "管理后台账户实体(平台管理员、租户管理员或商户员工)。");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedBy",
table: "mini_users",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "最后更新人用户标识,匿名或系统操作时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "mini_users",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true,
oldComment: "最近一次更新时间UTC从未更新时为 null。");
migrationBuilder.AlterColumn<string>(
name: "UnionId",
table: "mini_users",
type: "character varying(128)",
maxLength: 128,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(128)",
oldMaxLength: 128,
oldNullable: true,
oldComment: "微信 UnionId可能为空。");
migrationBuilder.AlterColumn<Guid>(
name: "TenantId",
table: "mini_users",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldComment: "所属租户 ID。");
migrationBuilder.AlterColumn<string>(
name: "OpenId",
table: "mini_users",
type: "character varying(128)",
maxLength: 128,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(128)",
oldMaxLength: 128,
oldComment: "微信 OpenId。");
migrationBuilder.AlterColumn<string>(
name: "Nickname",
table: "mini_users",
type: "character varying(64)",
maxLength: 64,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64,
oldComment: "昵称。");
migrationBuilder.AlterColumn<Guid>(
name: "DeletedBy",
table: "mini_users",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "删除人用户标识(软删除),未删除时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "DeletedAt",
table: "mini_users",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true,
oldComment: "软删除时间UTC未删除时为 null。");
migrationBuilder.AlterColumn<Guid>(
name: "CreatedBy",
table: "mini_users",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "创建人用户标识,匿名或系统操作时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "CreatedAt",
table: "mini_users",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldComment: "创建时间UTC。");
migrationBuilder.AlterColumn<string>(
name: "Avatar",
table: "mini_users",
type: "character varying(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256,
oldNullable: true,
oldComment: "头像地址。");
migrationBuilder.AlterColumn<Guid>(
name: "Id",
table: "mini_users",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldComment: "实体唯一标识。");
migrationBuilder.AlterColumn<Guid>(
name: "UpdatedBy",
table: "identity_users",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "最后更新人用户标识,匿名或系统操作时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "UpdatedAt",
table: "identity_users",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true,
oldComment: "最近一次更新时间UTC从未更新时为 null。");
migrationBuilder.AlterColumn<Guid>(
name: "TenantId",
table: "identity_users",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldComment: "所属租户 ID。");
migrationBuilder.AlterColumn<string>(
name: "Roles",
table: "identity_users",
type: "text",
nullable: false,
oldClrType: typeof(string),
oldType: "text",
oldComment: "角色集合。");
migrationBuilder.AlterColumn<string>(
name: "Permissions",
table: "identity_users",
type: "text",
nullable: false,
oldClrType: typeof(string),
oldType: "text",
oldComment: "权限集合。");
migrationBuilder.AlterColumn<string>(
name: "PasswordHash",
table: "identity_users",
type: "character varying(256)",
maxLength: 256,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256,
oldComment: "密码哈希。");
migrationBuilder.AlterColumn<Guid>(
name: "MerchantId",
table: "identity_users",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "所属商户(平台管理员为空)。");
migrationBuilder.AlterColumn<string>(
name: "DisplayName",
table: "identity_users",
type: "character varying(64)",
maxLength: 64,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64,
oldComment: "展示名称。");
migrationBuilder.AlterColumn<Guid>(
name: "DeletedBy",
table: "identity_users",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "删除人用户标识(软删除),未删除时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "DeletedAt",
table: "identity_users",
type: "timestamp with time zone",
nullable: true,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldNullable: true,
oldComment: "软删除时间UTC未删除时为 null。");
migrationBuilder.AlterColumn<Guid>(
name: "CreatedBy",
table: "identity_users",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true,
oldComment: "创建人用户标识,匿名或系统操作时为 null。");
migrationBuilder.AlterColumn<DateTime>(
name: "CreatedAt",
table: "identity_users",
type: "timestamp with time zone",
nullable: false,
oldClrType: typeof(DateTime),
oldType: "timestamp with time zone",
oldComment: "创建时间UTC。");
migrationBuilder.AlterColumn<string>(
name: "Avatar",
table: "identity_users",
type: "character varying(256)",
maxLength: 256,
nullable: true,
oldClrType: typeof(string),
oldType: "character varying(256)",
oldMaxLength: 256,
oldNullable: true,
oldComment: "头像地址。");
migrationBuilder.AlterColumn<string>(
name: "Account",
table: "identity_users",
type: "character varying(64)",
maxLength: 64,
nullable: false,
oldClrType: typeof(string),
oldType: "character varying(64)",
oldMaxLength: 64,
oldComment: "登录账号。");
migrationBuilder.AlterColumn<Guid>(
name: "Id",
table: "identity_users",
type: "uuid",
nullable: false,
oldClrType: typeof(Guid),
oldType: "uuid",
oldComment: "实体唯一标识。");
}
}
}

View File

@@ -26,58 +26,73 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("实体唯一标识。");
b.Property<string>("Account")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
.HasColumnType("character varying(64)")
.HasComment("登录账号。");
b.Property<string>("Avatar")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
.HasColumnType("character varying(256)")
.HasComment("头像地址。");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("创建时间UTC。");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("软删除时间UTC未删除时为 null。");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("删除人用户标识(软删除),未删除时为 null。");
b.Property<string>("DisplayName")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
.HasColumnType("character varying(64)")
.HasComment("展示名称。");
b.Property<Guid?>("MerchantId")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("所属商户(平台管理员为空)。");
b.Property<string>("PasswordHash")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("character varying(256)");
.HasColumnType("character varying(256)")
.HasComment("密码哈希。");
b.Property<string>("Permissions")
.IsRequired()
.HasColumnType("text");
.HasColumnType("text")
.HasComment("权限集合。");
b.Property<string>("Roles")
.IsRequired()
.HasColumnType("text");
.HasColumnType("text")
.HasComment("角色集合。");
b.Property<Guid>("TenantId")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("所属租户 ID。");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("最近一次更新时间UTC从未更新时为 null。");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
b.HasKey("Id");
@@ -86,53 +101,68 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
b.HasIndex("TenantId", "Account")
.IsUnique();
b.ToTable("identity_users", (string)null);
b.ToTable("identity_users", null, t =>
{
t.HasComment("管理后台账户实体(平台管理员、租户管理员或商户员工)。");
});
});
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.MiniUser", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("实体唯一标识。");
b.Property<string>("Avatar")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
.HasColumnType("character varying(256)")
.HasComment("头像地址。");
b.Property<DateTime>("CreatedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("创建时间UTC。");
b.Property<Guid?>("CreatedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
b.Property<DateTime?>("DeletedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("软删除时间UTC未删除时为 null。");
b.Property<Guid?>("DeletedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("删除人用户标识(软删除),未删除时为 null。");
b.Property<string>("Nickname")
.IsRequired()
.HasMaxLength(64)
.HasColumnType("character varying(64)");
.HasColumnType("character varying(64)")
.HasComment("昵称。");
b.Property<string>("OpenId")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("character varying(128)");
.HasColumnType("character varying(128)")
.HasComment("微信 OpenId。");
b.Property<Guid>("TenantId")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("所属租户 ID。");
b.Property<string>("UnionId")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
.HasColumnType("character varying(128)")
.HasComment("微信 UnionId可能为空。");
b.Property<DateTime?>("UpdatedAt")
.HasColumnType("timestamp with time zone");
.HasColumnType("timestamp with time zone")
.HasComment("最近一次更新时间UTC从未更新时为 null。");
b.Property<Guid?>("UpdatedBy")
.HasColumnType("uuid");
.HasColumnType("uuid")
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
b.HasKey("Id");
@@ -141,7 +171,10 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
b.HasIndex("TenantId", "OpenId")
.IsUnique();
b.ToTable("mini_users", (string)null);
b.ToTable("mini_users", null, t =>
{
t.HasComment("小程序用户实体。");
});
});
#pragma warning restore 612, 618
}

View File

@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Infrastructure.Common.Persistence.DesignTime;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
@@ -12,7 +13,7 @@ internal sealed class IdentityDesignTimeDbContextFactory
: DesignTimeDbContextFactoryBase<IdentityDbContext>
{
public IdentityDesignTimeDbContextFactory()
: base("TAKEOUTSAAS_IDENTITY_CONNECTION", "takeout_saas_identity")
: base(DatabaseConstants.IdentityDataSource, "TAKEOUTSAAS_IDENTITY_CONNECTION")
{
}