feat: migrate snowflake ids and refresh migrations
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TakeoutSaaS.Domain.Deliveries.Repositories;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Domain.Orders.Repositories;
|
||||
using TakeoutSaaS.Domain.Payments.Repositories;
|
||||
using TakeoutSaaS.Domain.Products.Repositories;
|
||||
using TakeoutSaaS.Domain.Stores.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.App.Options;
|
||||
using TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
using TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.Common.Extensions;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// 业务主库基础设施注册扩展。
|
||||
/// </summary>
|
||||
public static class AppServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册业务主库 DbContext 与仓储。
|
||||
/// </summary>
|
||||
/// <param name="services">服务集合。</param>
|
||||
/// <param name="configuration">配置源。</param>
|
||||
/// <returns>服务集合。</returns>
|
||||
public static IServiceCollection AddAppInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddDatabaseInfrastructure(configuration);
|
||||
services.AddPostgresDbContext<TakeoutAppDbContext>(DatabaseConstants.AppDataSource);
|
||||
|
||||
services.AddScoped<IMerchantRepository, EfMerchantRepository>();
|
||||
services.AddScoped<IStoreRepository, EfStoreRepository>();
|
||||
services.AddScoped<IProductRepository, EfProductRepository>();
|
||||
services.AddScoped<IOrderRepository, EfOrderRepository>();
|
||||
services.AddScoped<IPaymentRepository, EfPaymentRepository>();
|
||||
services.AddScoped<IDeliveryRepository, EfDeliveryRepository>();
|
||||
|
||||
services.AddOptions<AppSeedOptions>()
|
||||
.Bind(configuration.GetSection(AppSeedOptions.SectionName))
|
||||
.ValidateDataAnnotations();
|
||||
|
||||
services.AddHostedService<AppDataSeeder>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -1,949 +0,0 @@
|
||||
// <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.App.Persistence;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Migrations
|
||||
{
|
||||
[DbContext(typeof(TakeoutAppDbContext))]
|
||||
[Migration("20251201044927_InitialApp")]
|
||||
partial class InitialApp
|
||||
{
|
||||
/// <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.Deliveries.Entities.DeliveryOrder", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("CourierName")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("CourierPhone")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeliveredAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<decimal?>("DeliveryFee")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<DateTime?>("DispatchedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("FailureReason")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<Guid>("OrderId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("PickedUpAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int>("Provider")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ProviderOrderId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId", "OrderId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("delivery_orders", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Merchants.Entities.Merchant", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Address")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("BrandAlias")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("BrandName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("BusinessLicenseNumber")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("City")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ContactEmail")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("ContactPhone")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("District")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("LegalPerson")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime?>("OnboardedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Province")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ReviewRemarks")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.ToTable("merchants", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Orders.Entities.Order", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("CancelReason")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<DateTime?>("CancelledAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int>("Channel")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("CustomerName")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("CustomerPhone")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("DeliveryType")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<decimal>("DiscountAmount")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<DateTime?>("FinishedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<decimal>("ItemsAmount")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<string>("OrderNo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<decimal>("PaidAmount")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<DateTime?>("PaidAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<decimal>("PayableAmount")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<int>("PaymentStatus")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("QueueNumber")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<string>("Remark")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<Guid?>("ReservationId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("StoreId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("TableNo")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId", "OrderNo")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("TenantId", "StoreId", "Status");
|
||||
|
||||
b.ToTable("orders", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Orders.Entities.OrderItem", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("AttributesJson")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<decimal>("DiscountAmount")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<Guid>("OrderId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("ProductId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("ProductName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("SkuName")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<decimal>("SubTotal")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Unit")
|
||||
.HasMaxLength(16)
|
||||
.HasColumnType("character varying(16)");
|
||||
|
||||
b.Property<decimal>("UnitPrice")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.HasIndex("TenantId", "OrderId");
|
||||
|
||||
b.ToTable("order_items", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Payments.Entities.PaymentRecord", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<string>("ChannelTransactionId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("Method")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("OrderId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("PaidAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Payload")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Remark")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("TradeNo")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId", "OrderId");
|
||||
|
||||
b.ToTable("payment_records", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Products.Entities.Product", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("CategoryId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("CoverImage")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("EnableDelivery")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("EnableDineIn")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("EnablePickup")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("GalleryImages")
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("character varying(1024)");
|
||||
|
||||
b.Property<bool>("IsFeatured")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int?>("MaxQuantityPerOrder")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<decimal?>("OriginalPrice")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<decimal>("Price")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("numeric(18,2)");
|
||||
|
||||
b.Property<string>("SpuCode")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int?>("StockQuantity")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("StoreId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Subtitle")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Unit")
|
||||
.HasMaxLength(16)
|
||||
.HasColumnType("character varying(16)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId", "SpuCode")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("TenantId", "StoreId");
|
||||
|
||||
b.ToTable("products", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Products.Entities.ProductCategory", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("StoreId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId", "StoreId");
|
||||
|
||||
b.ToTable("product_categories", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Queues.Entities.QueueTicket", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("CalledAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("CancelledAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int?>("EstimatedWaitMinutes")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<DateTime?>("ExpiredAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int>("PartySize")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Remark")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("StoreId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("TicketNumber")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId", "StoreId");
|
||||
|
||||
b.HasIndex("TenantId", "StoreId", "TicketNumber")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("queue_tickets", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Reservations.Entities.Reservation", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("CancelledAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("CheckInCode")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<DateTime?>("CheckedInAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("CustomerName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("CustomerPhone")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<int>("PeopleCount")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Remark")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("ReservationNo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<DateTime>("ReservationTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("StoreId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("TablePreference")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId", "ReservationNo")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("TenantId", "StoreId");
|
||||
|
||||
b.ToTable("reservations", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Stores.Entities.Store", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Address")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("Announcement")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("BusinessHours")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("City")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<decimal>("DeliveryRadiusKm")
|
||||
.HasPrecision(6, 2)
|
||||
.HasColumnType("numeric(6,2)");
|
||||
|
||||
b.Property<string>("District")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<double?>("Latitude")
|
||||
.HasColumnType("double precision");
|
||||
|
||||
b.Property<double?>("Longitude")
|
||||
.HasColumnType("double precision");
|
||||
|
||||
b.Property<string>("ManagerName")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<Guid>("MerchantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<string>("Province")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<bool>("QueueEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("ReservationEnabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool>("SupportsDelivery")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("SupportsDineIn")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("SupportsPickup")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("MerchantId");
|
||||
|
||||
b.HasIndex("TenantId", "Code")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("TenantId", "MerchantId");
|
||||
|
||||
b.ToTable("stores", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Tenants.Entities.Tenant", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ContactEmail")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("ContactName")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("ContactPhone")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("EffectiveFrom")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<DateTime?>("EffectiveTo")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Industry")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("LogoUrl")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<string>("Remarks")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<string>("ShortName")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Code")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("tenants", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Orders.Entities.OrderItem", b =>
|
||||
{
|
||||
b.HasOne("TakeoutSaaS.Domain.Orders.Entities.Order", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Stores.Entities.Store", b =>
|
||||
{
|
||||
b.HasOne("TakeoutSaaS.Domain.Merchants.Entities.Merchant", "Merchant")
|
||||
.WithMany()
|
||||
.HasForeignKey("MerchantId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Merchant");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,497 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialApp : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "delivery_orders",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
OrderId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Provider = table.Column<int>(type: "integer", nullable: false),
|
||||
ProviderOrderId = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
Status = table.Column<int>(type: "integer", nullable: false),
|
||||
DeliveryFee = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: true),
|
||||
CourierName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
CourierPhone = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
DispatchedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
PickedUpAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeliveredAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
FailureReason = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_delivery_orders", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "merchants",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
BrandName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||
BrandAlias = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
LegalPerson = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
BusinessLicenseNumber = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
ContactPhone = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
ContactEmail = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||
Province = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
City = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
District = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
Address = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
Status = table.Column<int>(type: "integer", nullable: false),
|
||||
ReviewRemarks = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
|
||||
OnboardedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_merchants", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "orders",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
OrderNo = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
StoreId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Channel = table.Column<int>(type: "integer", nullable: false),
|
||||
DeliveryType = table.Column<int>(type: "integer", nullable: false),
|
||||
Status = table.Column<int>(type: "integer", nullable: false),
|
||||
PaymentStatus = table.Column<int>(type: "integer", nullable: false),
|
||||
CustomerName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
CustomerPhone = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
TableNo = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
QueueNumber = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
ReservationId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
ItemsAmount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
DiscountAmount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
PayableAmount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
PaidAmount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
PaidAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
FinishedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CancelledAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CancelReason = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
Remark = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_orders", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "payment_records",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
OrderId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Method = table.Column<int>(type: "integer", nullable: false),
|
||||
Status = table.Column<int>(type: "integer", nullable: false),
|
||||
Amount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
TradeNo = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
ChannelTransactionId = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
PaidAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
Remark = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
Payload = table.Column<string>(type: "text", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_payment_records", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "product_categories",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
StoreId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
Description = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
SortOrder = table.Column<int>(type: "integer", nullable: false),
|
||||
IsEnabled = table.Column<bool>(type: "boolean", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_product_categories", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "products",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
StoreId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
CategoryId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
SpuCode = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||
Subtitle = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
Unit = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: true),
|
||||
Price = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
OriginalPrice = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: true),
|
||||
StockQuantity = table.Column<int>(type: "integer", nullable: true),
|
||||
MaxQuantityPerOrder = table.Column<int>(type: "integer", nullable: true),
|
||||
Status = table.Column<int>(type: "integer", nullable: false),
|
||||
CoverImage = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
GalleryImages = table.Column<string>(type: "character varying(1024)", maxLength: 1024, nullable: true),
|
||||
Description = table.Column<string>(type: "text", nullable: true),
|
||||
EnableDineIn = table.Column<bool>(type: "boolean", nullable: false),
|
||||
EnablePickup = table.Column<bool>(type: "boolean", nullable: false),
|
||||
EnableDelivery = table.Column<bool>(type: "boolean", nullable: false),
|
||||
IsFeatured = table.Column<bool>(type: "boolean", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_products", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "queue_tickets",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
StoreId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
TicketNumber = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
PartySize = table.Column<int>(type: "integer", nullable: false),
|
||||
Status = table.Column<int>(type: "integer", nullable: false),
|
||||
EstimatedWaitMinutes = table.Column<int>(type: "integer", nullable: true),
|
||||
CalledAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
ExpiredAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CancelledAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
Remark = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_queue_tickets", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "reservations",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
StoreId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ReservationNo = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
CustomerName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
CustomerPhone = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
PeopleCount = table.Column<int>(type: "integer", nullable: false),
|
||||
ReservationTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
Status = table.Column<int>(type: "integer", nullable: false),
|
||||
TablePreference = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
Remark = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
|
||||
CheckInCode = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
CheckedInAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CancelledAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_reservations", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "tenants",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Code = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||
ShortName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
ContactName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
ContactPhone = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
ContactEmail = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||
Industry = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
LogoUrl = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
EffectiveFrom = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
EffectiveTo = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
Status = table.Column<int>(type: "integer", nullable: false),
|
||||
Remarks = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_tenants", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "stores",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
MerchantId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Code = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||
Phone = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
ManagerName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
Status = table.Column<int>(type: "integer", nullable: false),
|
||||
Province = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
City = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
District = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
Address = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
Longitude = table.Column<double>(type: "double precision", nullable: true),
|
||||
Latitude = table.Column<double>(type: "double precision", nullable: true),
|
||||
BusinessHours = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
SupportsDineIn = table.Column<bool>(type: "boolean", nullable: false),
|
||||
SupportsPickup = table.Column<bool>(type: "boolean", nullable: false),
|
||||
SupportsDelivery = table.Column<bool>(type: "boolean", nullable: false),
|
||||
DeliveryRadiusKm = table.Column<decimal>(type: "numeric(6,2)", precision: 6, scale: 2, nullable: false),
|
||||
QueueEnabled = table.Column<bool>(type: "boolean", nullable: false),
|
||||
ReservationEnabled = table.Column<bool>(type: "boolean", nullable: false),
|
||||
Announcement = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_stores", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_stores_merchants_MerchantId",
|
||||
column: x => x.MerchantId,
|
||||
principalTable: "merchants",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "order_items",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
OrderId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ProductId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ProductName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||
SkuName = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||
Unit = table.Column<string>(type: "character varying(16)", maxLength: 16, nullable: true),
|
||||
Quantity = table.Column<int>(type: "integer", nullable: false),
|
||||
UnitPrice = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
DiscountAmount = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
SubTotal = table.Column<decimal>(type: "numeric(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
AttributesJson = table.Column<string>(type: "text", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_order_items", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_order_items_orders_OrderId",
|
||||
column: x => x.OrderId,
|
||||
principalTable: "orders",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_delivery_orders_TenantId_OrderId",
|
||||
table: "delivery_orders",
|
||||
columns: new[] { "TenantId", "OrderId" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_merchants_TenantId",
|
||||
table: "merchants",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_order_items_OrderId",
|
||||
table: "order_items",
|
||||
column: "OrderId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_order_items_TenantId_OrderId",
|
||||
table: "order_items",
|
||||
columns: new[] { "TenantId", "OrderId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_orders_TenantId_OrderNo",
|
||||
table: "orders",
|
||||
columns: new[] { "TenantId", "OrderNo" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_orders_TenantId_StoreId_Status",
|
||||
table: "orders",
|
||||
columns: new[] { "TenantId", "StoreId", "Status" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_payment_records_TenantId_OrderId",
|
||||
table: "payment_records",
|
||||
columns: new[] { "TenantId", "OrderId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_product_categories_TenantId_StoreId",
|
||||
table: "product_categories",
|
||||
columns: new[] { "TenantId", "StoreId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_products_TenantId_SpuCode",
|
||||
table: "products",
|
||||
columns: new[] { "TenantId", "SpuCode" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_products_TenantId_StoreId",
|
||||
table: "products",
|
||||
columns: new[] { "TenantId", "StoreId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_queue_tickets_TenantId_StoreId",
|
||||
table: "queue_tickets",
|
||||
columns: new[] { "TenantId", "StoreId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_queue_tickets_TenantId_StoreId_TicketNumber",
|
||||
table: "queue_tickets",
|
||||
columns: new[] { "TenantId", "StoreId", "TicketNumber" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_reservations_TenantId_ReservationNo",
|
||||
table: "reservations",
|
||||
columns: new[] { "TenantId", "ReservationNo" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_reservations_TenantId_StoreId",
|
||||
table: "reservations",
|
||||
columns: new[] { "TenantId", "StoreId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_stores_MerchantId",
|
||||
table: "stores",
|
||||
column: "MerchantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_stores_TenantId_Code",
|
||||
table: "stores",
|
||||
columns: new[] { "TenantId", "Code" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_stores_TenantId_MerchantId",
|
||||
table: "stores",
|
||||
columns: new[] { "TenantId", "MerchantId" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_tenants_Code",
|
||||
table: "tenants",
|
||||
column: "Code",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "delivery_orders");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "order_items");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "payment_records");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "product_categories");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "products");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "queue_tickets");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "reservations");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "stores");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "tenants");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "orders");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "merchants");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Options;
|
||||
|
||||
/// <summary>
|
||||
/// 业务数据种子配置。
|
||||
/// </summary>
|
||||
public sealed class AppSeedOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置节名称。
|
||||
/// </summary>
|
||||
public const string SectionName = "App:Seed";
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用业务数据种子。
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 默认租户配置。
|
||||
/// </summary>
|
||||
public TenantSeedOptions? DefaultTenant { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 基础字典分组。
|
||||
/// </summary>
|
||||
public List<DictionarySeedGroupOptions> DictionaryGroups { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using TakeoutSaaS.Domain.Dictionary.Enums;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Options;
|
||||
|
||||
/// <summary>
|
||||
/// 字典分组种子配置。
|
||||
/// </summary>
|
||||
public sealed class DictionarySeedGroupOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 所属租户,不填则使用默认租户或系统租户。
|
||||
/// </summary>
|
||||
public long? TenantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分组编码。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(64)]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 分组名称。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(128)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 分组作用域。
|
||||
/// </summary>
|
||||
public DictionaryScope Scope { get; set; } = DictionaryScope.Business;
|
||||
|
||||
/// <summary>
|
||||
/// 描述信息。
|
||||
/// </summary>
|
||||
[MaxLength(512)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用。
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 字典项集合。
|
||||
/// </summary>
|
||||
public List<DictionarySeedItemOptions> Items { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Options;
|
||||
|
||||
/// <summary>
|
||||
/// 字典项种子配置。
|
||||
/// </summary>
|
||||
public sealed class DictionarySeedItemOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典项键。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(64)]
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 字典项值。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(256)]
|
||||
public string Value { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 描述。
|
||||
/// </summary>
|
||||
[MaxLength(512)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序。
|
||||
/// </summary>
|
||||
public int SortOrder { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用。
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Options;
|
||||
|
||||
/// <summary>
|
||||
/// 默认租户种子配置。
|
||||
/// </summary>
|
||||
public sealed class TenantSeedOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// 自定义租户标识,不填则自动生成。
|
||||
/// </summary>
|
||||
public long TenantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 租户编码。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(64)]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 租户名称。
|
||||
/// </summary>
|
||||
[Required]
|
||||
[MaxLength(128)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 租户简称。
|
||||
/// </summary>
|
||||
[MaxLength(128)]
|
||||
public string? ShortName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 联系人姓名。
|
||||
/// </summary>
|
||||
[MaxLength(64)]
|
||||
public string? ContactName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 联系电话。
|
||||
/// </summary>
|
||||
[MaxLength(32)]
|
||||
public string? ContactPhone { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using TakeoutSaaS.Domain.Dictionary.Entities;
|
||||
using TakeoutSaaS.Domain.Tenants.Entities;
|
||||
using TakeoutSaaS.Domain.Tenants.Enums;
|
||||
using TakeoutSaaS.Infrastructure.App.Options;
|
||||
using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
/// <summary>
|
||||
/// 业务数据种子,确保默认租户与基础字典可重复执行。
|
||||
/// </summary>
|
||||
public sealed class AppDataSeeder : IHostedService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<AppDataSeeder> _logger;
|
||||
private readonly AppSeedOptions _options;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化种子服务。
|
||||
/// </summary>
|
||||
public AppDataSeeder(
|
||||
IServiceProvider serviceProvider,
|
||||
ILogger<AppDataSeeder> logger,
|
||||
IOptions<AppSeedOptions> options)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!_options.Enabled)
|
||||
{
|
||||
_logger.LogInformation("AppSeed 未启用,跳过业务数据初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var appDbContext = scope.ServiceProvider.GetRequiredService<TakeoutAppDbContext>();
|
||||
var dictionaryDbContext = scope.ServiceProvider.GetRequiredService<DictionaryDbContext>();
|
||||
|
||||
var defaultTenantId = await EnsureDefaultTenantAsync(appDbContext, cancellationToken);
|
||||
await EnsureDictionarySeedsAsync(dictionaryDbContext, defaultTenantId, cancellationToken);
|
||||
|
||||
_logger.LogInformation("AppSeed 完成业务数据初始化");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// 确保默认租户存在。
|
||||
/// </summary>
|
||||
private async Task<long?> EnsureDefaultTenantAsync(TakeoutAppDbContext dbContext, CancellationToken cancellationToken)
|
||||
{
|
||||
var tenantOptions = _options.DefaultTenant;
|
||||
if (tenantOptions == null || string.IsNullOrWhiteSpace(tenantOptions.Code) || string.IsNullOrWhiteSpace(tenantOptions.Name))
|
||||
{
|
||||
_logger.LogInformation("AppSeed 未配置默认租户,跳过租户种子");
|
||||
return null;
|
||||
}
|
||||
|
||||
var code = tenantOptions.Code.Trim();
|
||||
var existingTenant = await dbContext.Tenants
|
||||
.IgnoreQueryFilters()
|
||||
.FirstOrDefaultAsync(x => x.Code == code, cancellationToken);
|
||||
|
||||
if (existingTenant == null)
|
||||
{
|
||||
var tenant = new Tenant
|
||||
{
|
||||
Id = tenantOptions.TenantId,
|
||||
Code = code,
|
||||
Name = tenantOptions.Name.Trim(),
|
||||
ShortName = tenantOptions.ShortName?.Trim(),
|
||||
ContactName = tenantOptions.ContactName?.Trim(),
|
||||
ContactPhone = tenantOptions.ContactPhone?.Trim(),
|
||||
Status = TenantStatus.Active
|
||||
};
|
||||
|
||||
await dbContext.Tenants.AddAsync(tenant, cancellationToken);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
_logger.LogInformation("AppSeed 已创建默认租户 {TenantCode}", code);
|
||||
return tenant.Id;
|
||||
}
|
||||
|
||||
var updated = false;
|
||||
|
||||
if (!string.Equals(existingTenant.Name, tenantOptions.Name, StringComparison.Ordinal))
|
||||
{
|
||||
existingTenant.Name = tenantOptions.Name.Trim();
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (!string.Equals(existingTenant.ShortName, tenantOptions.ShortName, StringComparison.Ordinal))
|
||||
{
|
||||
existingTenant.ShortName = tenantOptions.ShortName?.Trim();
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (!string.Equals(existingTenant.ContactName, tenantOptions.ContactName, StringComparison.Ordinal))
|
||||
{
|
||||
existingTenant.ContactName = tenantOptions.ContactName?.Trim();
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (!string.Equals(existingTenant.ContactPhone, tenantOptions.ContactPhone, StringComparison.Ordinal))
|
||||
{
|
||||
existingTenant.ContactPhone = tenantOptions.ContactPhone?.Trim();
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (existingTenant.Status != TenantStatus.Active)
|
||||
{
|
||||
existingTenant.Status = TenantStatus.Active;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
dbContext.Tenants.Update(existingTenant);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
_logger.LogInformation("AppSeed 已更新默认租户 {TenantCode}", code);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("AppSeed 默认租户 {TenantCode} 已存在且无需更新", code);
|
||||
}
|
||||
|
||||
return existingTenant.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确保基础字典存在。
|
||||
/// </summary>
|
||||
private async Task EnsureDictionarySeedsAsync(DictionaryDbContext dbContext, long? defaultTenantId, CancellationToken cancellationToken)
|
||||
{
|
||||
if (_options.DictionaryGroups == null || _options.DictionaryGroups.Count == 0)
|
||||
{
|
||||
_logger.LogInformation("AppSeed 未配置基础字典,跳过字典种子");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var groupOptions in _options.DictionaryGroups)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(groupOptions.Code) || string.IsNullOrWhiteSpace(groupOptions.Name))
|
||||
{
|
||||
_logger.LogWarning("AppSeed 跳过字典分组,Code 或 Name 为空");
|
||||
continue;
|
||||
}
|
||||
|
||||
var tenantId = groupOptions.TenantId ?? defaultTenantId ?? 0;
|
||||
var code = groupOptions.Code.Trim();
|
||||
|
||||
var group = await dbContext.DictionaryGroups
|
||||
.IgnoreQueryFilters()
|
||||
.FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Code == code, cancellationToken);
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
group = new DictionaryGroup
|
||||
{
|
||||
Id = 0,
|
||||
TenantId = tenantId,
|
||||
Code = code,
|
||||
Name = groupOptions.Name.Trim(),
|
||||
Scope = groupOptions.Scope,
|
||||
Description = groupOptions.Description?.Trim(),
|
||||
IsEnabled = groupOptions.IsEnabled
|
||||
};
|
||||
|
||||
await dbContext.DictionaryGroups.AddAsync(group, cancellationToken);
|
||||
_logger.LogInformation("AppSeed 创建字典分组 {GroupCode} (Tenant: {TenantId})", code, tenantId);
|
||||
}
|
||||
else
|
||||
{
|
||||
var groupUpdated = false;
|
||||
|
||||
if (!string.Equals(group.Name, groupOptions.Name, StringComparison.Ordinal))
|
||||
{
|
||||
group.Name = groupOptions.Name.Trim();
|
||||
groupUpdated = true;
|
||||
}
|
||||
|
||||
if (!string.Equals(group.Description, groupOptions.Description, StringComparison.Ordinal))
|
||||
{
|
||||
group.Description = groupOptions.Description?.Trim();
|
||||
groupUpdated = true;
|
||||
}
|
||||
|
||||
if (group.Scope != groupOptions.Scope)
|
||||
{
|
||||
group.Scope = groupOptions.Scope;
|
||||
groupUpdated = true;
|
||||
}
|
||||
|
||||
if (group.IsEnabled != groupOptions.IsEnabled)
|
||||
{
|
||||
group.IsEnabled = groupOptions.IsEnabled;
|
||||
groupUpdated = true;
|
||||
}
|
||||
|
||||
if (groupUpdated)
|
||||
{
|
||||
dbContext.DictionaryGroups.Update(group);
|
||||
}
|
||||
}
|
||||
|
||||
await UpsertDictionaryItemsAsync(dbContext, group, groupOptions.Items, tenantId, cancellationToken);
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 合并字典项。
|
||||
/// </summary>
|
||||
private static async Task UpsertDictionaryItemsAsync(
|
||||
DictionaryDbContext dbContext,
|
||||
DictionaryGroup group,
|
||||
IEnumerable<DictionarySeedItemOptions> seedItems,
|
||||
long tenantId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var materializedItems = seedItems
|
||||
.Where(item => !string.IsNullOrWhiteSpace(item.Key) && !string.IsNullOrWhiteSpace(item.Value))
|
||||
.ToList();
|
||||
|
||||
if (materializedItems.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var existingItems = await dbContext.DictionaryItems
|
||||
.IgnoreQueryFilters()
|
||||
.Where(x => x.GroupId == group.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
foreach (var seed in materializedItems)
|
||||
{
|
||||
var key = seed.Key.Trim();
|
||||
var existing = existingItems.FirstOrDefault(x => x.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (existing == null)
|
||||
{
|
||||
var newItem = new DictionaryItem
|
||||
{
|
||||
Id = 0,
|
||||
TenantId = tenantId,
|
||||
GroupId = group.Id,
|
||||
Key = key,
|
||||
Value = seed.Value.Trim(),
|
||||
Description = seed.Description?.Trim(),
|
||||
SortOrder = seed.SortOrder,
|
||||
IsEnabled = seed.IsEnabled
|
||||
};
|
||||
|
||||
await dbContext.DictionaryItems.AddAsync(newItem, cancellationToken);
|
||||
continue;
|
||||
}
|
||||
|
||||
var updated = false;
|
||||
|
||||
if (!string.Equals(existing.Value, seed.Value, StringComparison.Ordinal))
|
||||
{
|
||||
existing.Value = seed.Value.Trim();
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (!string.Equals(existing.Description, seed.Description, StringComparison.Ordinal))
|
||||
{
|
||||
existing.Description = seed.Description?.Trim();
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (existing.SortOrder != seed.SortOrder)
|
||||
{
|
||||
existing.SortOrder = seed.SortOrder;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (existing.IsEnabled != seed.IsEnabled)
|
||||
{
|
||||
existing.IsEnabled = seed.IsEnabled;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
dbContext.DictionaryItems.Update(existing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ using TakeoutSaaS.Domain.Reservations.Entities;
|
||||
using TakeoutSaaS.Domain.Stores.Entities;
|
||||
using TakeoutSaaS.Domain.Tenants.Entities;
|
||||
using TakeoutSaaS.Infrastructure.Common.Persistence;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
@@ -31,8 +32,9 @@ namespace TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
public sealed class TakeoutAppDbContext(
|
||||
DbContextOptions<TakeoutAppDbContext> options,
|
||||
ITenantProvider tenantProvider,
|
||||
ICurrentUserAccessor? currentUserAccessor = null)
|
||||
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor)
|
||||
ICurrentUserAccessor? currentUserAccessor = null,
|
||||
IIdGenerator? idGenerator = null)
|
||||
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
|
||||
{
|
||||
public DbSet<Tenant> Tenants => Set<Tenant>();
|
||||
public DbSet<TenantPackage> TenantPackages => Set<TenantPackage>();
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Deliveries.Entities;
|
||||
using TakeoutSaaS.Domain.Deliveries.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 配送聚合的 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfDeliveryRepository : IDeliveryRepository
|
||||
{
|
||||
private readonly TakeoutAppDbContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化仓储。
|
||||
/// </summary>
|
||||
public EfDeliveryRepository(TakeoutAppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<DeliveryOrder?> FindByIdAsync(long deliveryOrderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.DeliveryOrders
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.Id == deliveryOrderId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<DeliveryOrder?> FindByOrderIdAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.DeliveryOrders
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.OrderId == orderId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<DeliveryEvent>> GetEventsAsync(long deliveryOrderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var events = await _context.DeliveryEvents
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.DeliveryOrderId == deliveryOrderId)
|
||||
.OrderBy(x => x.CreatedAt)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddDeliveryOrderAsync(DeliveryOrder deliveryOrder, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.DeliveryOrders.AddAsync(deliveryOrder, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddEventAsync(DeliveryEvent deliveryEvent, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.DeliveryEvents.AddAsync(deliveryEvent, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Merchants.Entities;
|
||||
using TakeoutSaaS.Domain.Merchants.Enums;
|
||||
using TakeoutSaaS.Domain.Merchants.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 商户聚合的 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfMerchantRepository : IMerchantRepository
|
||||
{
|
||||
private readonly TakeoutAppDbContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化仓储。
|
||||
/// </summary>
|
||||
public EfMerchantRepository(TakeoutAppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Merchant?> FindByIdAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.Merchants
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.Id == merchantId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<Merchant>> SearchAsync(long tenantId, MerchantStatus? status, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = _context.Merchants
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId);
|
||||
|
||||
if (status.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.Status == status.Value);
|
||||
}
|
||||
|
||||
return await query
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.ToListAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<MerchantStaff>> GetStaffAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var staffs = await _context.MerchantStaff
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
|
||||
.OrderBy(x => x.Name)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return staffs;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<MerchantContract>> GetContractsAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var contracts = await _context.MerchantContracts
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return contracts;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<MerchantDocument>> GetDocumentsAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var documents = await _context.MerchantDocuments
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
|
||||
.OrderBy(x => x.CreatedAt)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return documents;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddMerchantAsync(Merchant merchant, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.Merchants.AddAsync(merchant, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddStaffAsync(MerchantStaff staff, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.MerchantStaff.AddAsync(staff, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddContractAsync(MerchantContract contract, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.MerchantContracts.AddAsync(contract, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddDocumentAsync(MerchantDocument document, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.MerchantDocuments.AddAsync(document, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Orders.Entities;
|
||||
using TakeoutSaaS.Domain.Orders.Enums;
|
||||
using TakeoutSaaS.Domain.Orders.Repositories;
|
||||
using TakeoutSaaS.Domain.Payments.Enums;
|
||||
using TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 订单聚合的 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfOrderRepository : IOrderRepository
|
||||
{
|
||||
private readonly TakeoutAppDbContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化仓储。
|
||||
/// </summary>
|
||||
public EfOrderRepository(TakeoutAppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Order?> FindByIdAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.Orders
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.Id == orderId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Order?> FindByOrderNoAsync(string orderNo, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.Orders
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.OrderNo == orderNo)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<Order>> SearchAsync(long tenantId, OrderStatus? status, PaymentStatus? paymentStatus, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = _context.Orders
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId);
|
||||
|
||||
if (status.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.Status == status.Value);
|
||||
}
|
||||
|
||||
if (paymentStatus.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.PaymentStatus == paymentStatus.Value);
|
||||
}
|
||||
|
||||
var orders = await query
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return orders;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<OrderItem>> GetItemsAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var items = await _context.OrderItems
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.OrderId == orderId)
|
||||
.OrderBy(x => x.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<OrderStatusHistory>> GetStatusHistoryAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var histories = await _context.OrderStatusHistories
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.OrderId == orderId)
|
||||
.OrderBy(x => x.CreatedAt)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return histories;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<RefundRequest>> GetRefundsAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var refunds = await _context.RefundRequests
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.OrderId == orderId)
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return refunds;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddOrderAsync(Order order, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.Orders.AddAsync(order, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddItemsAsync(IEnumerable<OrderItem> items, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.OrderItems.AddRangeAsync(items, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddStatusHistoryAsync(OrderStatusHistory history, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.OrderStatusHistories.AddAsync(history, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddRefundAsync(RefundRequest refund, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.RefundRequests.AddAsync(refund, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Payments.Entities;
|
||||
using TakeoutSaaS.Domain.Payments.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 支付记录的 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfPaymentRepository : IPaymentRepository
|
||||
{
|
||||
private readonly TakeoutAppDbContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化仓储。
|
||||
/// </summary>
|
||||
public EfPaymentRepository(TakeoutAppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<PaymentRecord?> FindByIdAsync(long paymentId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.PaymentRecords
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.Id == paymentId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<PaymentRecord?> FindByOrderIdAsync(long orderId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.PaymentRecords
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.OrderId == orderId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<PaymentRefundRecord>> GetRefundsAsync(long paymentId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var refunds = await _context.PaymentRefundRecords
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.PaymentRecordId == paymentId)
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return refunds;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddPaymentAsync(PaymentRecord payment, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.PaymentRecords.AddAsync(payment, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddRefundAsync(PaymentRefundRecord refund, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.PaymentRefundRecords.AddAsync(refund, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Products.Entities;
|
||||
using TakeoutSaaS.Domain.Products.Enums;
|
||||
using TakeoutSaaS.Domain.Products.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 商品聚合的 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfProductRepository : IProductRepository
|
||||
{
|
||||
private readonly TakeoutAppDbContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化仓储。
|
||||
/// </summary>
|
||||
public EfProductRepository(TakeoutAppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Product?> FindByIdAsync(long productId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.Products
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.Id == productId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<Product>> SearchAsync(long tenantId, long? categoryId, ProductStatus? status, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = _context.Products
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId);
|
||||
|
||||
if (categoryId.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.CategoryId == categoryId.Value);
|
||||
}
|
||||
|
||||
if (status.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.Status == status.Value);
|
||||
}
|
||||
|
||||
var products = await query
|
||||
.OrderBy(x => x.Name)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return products;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<ProductCategory>> GetCategoriesAsync(long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var categories = await _context.ProductCategories
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<ProductSku>> GetSkusAsync(long productId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var skus = await _context.ProductSkus
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.ProductId == productId)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return skus;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<ProductAddonGroup>> GetAddonGroupsAsync(long productId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var groups = await _context.ProductAddonGroups
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.ProductId == productId)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<ProductAddonOption>> GetAddonOptionsAsync(long productId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var groupIds = await _context.ProductAddonGroups
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.ProductId == productId)
|
||||
.Select(x => x.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (groupIds.Count == 0)
|
||||
{
|
||||
return Array.Empty<ProductAddonOption>();
|
||||
}
|
||||
|
||||
var options = await _context.ProductAddonOptions
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && groupIds.Contains(x.AddonGroupId))
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<ProductAttributeGroup>> GetAttributeGroupsAsync(long productId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var groups = await _context.ProductAttributeGroups
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.ProductId == productId)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<ProductAttributeOption>> GetAttributeOptionsAsync(long productId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var groupIds = await _context.ProductAttributeGroups
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.ProductId == productId)
|
||||
.Select(x => x.Id)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
if (groupIds.Count == 0)
|
||||
{
|
||||
return Array.Empty<ProductAttributeOption>();
|
||||
}
|
||||
|
||||
var options = await _context.ProductAttributeOptions
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && groupIds.Contains(x.AttributeGroupId))
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<ProductMediaAsset>> GetMediaAssetsAsync(long productId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var assets = await _context.ProductMediaAssets
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.ProductId == productId)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return assets;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<ProductPricingRule>> GetPricingRulesAsync(long productId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var rules = await _context.ProductPricingRules
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.ProductId == productId)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddCategoryAsync(ProductCategory category, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.ProductCategories.AddAsync(category, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddProductAsync(Product product, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.Products.AddAsync(product, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddSkusAsync(IEnumerable<ProductSku> skus, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.ProductSkus.AddRangeAsync(skus, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddAddonGroupsAsync(IEnumerable<ProductAddonGroup> groups, IEnumerable<ProductAddonOption> options, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var addGroupsTask = _context.ProductAddonGroups.AddRangeAsync(groups, cancellationToken);
|
||||
var addOptionsTask = _context.ProductAddonOptions.AddRangeAsync(options, cancellationToken);
|
||||
return Task.WhenAll(addGroupsTask, addOptionsTask);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddAttributeGroupsAsync(IEnumerable<ProductAttributeGroup> groups, IEnumerable<ProductAttributeOption> options, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var addGroupsTask = _context.ProductAttributeGroups.AddRangeAsync(groups, cancellationToken);
|
||||
var addOptionsTask = _context.ProductAttributeOptions.AddRangeAsync(options, cancellationToken);
|
||||
return Task.WhenAll(addGroupsTask, addOptionsTask);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddMediaAssetsAsync(IEnumerable<ProductMediaAsset> assets, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.ProductMediaAssets.AddRangeAsync(assets, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddPricingRulesAsync(IEnumerable<ProductPricingRule> rules, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.ProductPricingRules.AddRangeAsync(rules, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.Stores.Entities;
|
||||
using TakeoutSaaS.Domain.Stores.Enums;
|
||||
using TakeoutSaaS.Domain.Stores.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.App.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.App.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 门店聚合的 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfStoreRepository : IStoreRepository
|
||||
{
|
||||
private readonly TakeoutAppDbContext _context;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化仓储。
|
||||
/// </summary>
|
||||
public EfStoreRepository(TakeoutAppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Store?> FindByIdAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.Stores
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.Id == storeId)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<Store>> SearchAsync(long tenantId, StoreStatus? status, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = _context.Stores
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId);
|
||||
|
||||
if (status.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.Status == status.Value);
|
||||
}
|
||||
|
||||
var stores = await query
|
||||
.OrderBy(x => x.Name)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return stores;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<StoreBusinessHour>> GetBusinessHoursAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var hours = await _context.StoreBusinessHours
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
||||
.OrderBy(x => x.DayOfWeek)
|
||||
.ThenBy(x => x.StartTime)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return hours;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<StoreDeliveryZone>> GetDeliveryZonesAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var zones = await _context.StoreDeliveryZones
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return zones;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<StoreHoliday>> GetHolidaysAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var holidays = await _context.StoreHolidays
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
||||
.OrderBy(x => x.Date)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return holidays;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<StoreTableArea>> GetTableAreasAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var areas = await _context.StoreTableAreas
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return areas;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<StoreTable>> GetTablesAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var tables = await _context.StoreTables
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
||||
.OrderBy(x => x.TableCode)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return tables;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<StoreEmployeeShift>> GetShiftsAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var shifts = await _context.StoreEmployeeShifts
|
||||
.AsNoTracking()
|
||||
.Where(x => x.TenantId == tenantId && x.StoreId == storeId)
|
||||
.OrderBy(x => x.ShiftDate)
|
||||
.ThenBy(x => x.StartTime)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return shifts;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddStoreAsync(Store store, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.Stores.AddAsync(store, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddBusinessHoursAsync(IEnumerable<StoreBusinessHour> hours, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.StoreBusinessHours.AddRangeAsync(hours, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddDeliveryZonesAsync(IEnumerable<StoreDeliveryZone> zones, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.StoreDeliveryZones.AddRangeAsync(zones, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddHolidaysAsync(IEnumerable<StoreHoliday> holidays, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.StoreHolidays.AddRangeAsync(holidays, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddTableAreasAsync(IEnumerable<StoreTableArea> areas, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.StoreTableAreas.AddRangeAsync(areas, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddTablesAsync(IEnumerable<StoreTable> tables, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.StoreTables.AddRangeAsync(tables, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddShiftsAsync(IEnumerable<StoreEmployeeShift> shifts, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.StoreEmployeeShifts.AddRangeAsync(shifts, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TakeoutSaaS.Infrastructure.Common.Options;
|
||||
using TakeoutSaaS.Infrastructure.Common.Persistence;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
using TakeoutSaaS.Shared.Abstractions.Data;
|
||||
using TakeoutSaaS.Shared.Kernel.Ids;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Common.Extensions;
|
||||
|
||||
@@ -25,6 +27,17 @@ public static class DatabaseServiceCollectionExtensions
|
||||
.ValidateDataAnnotations()
|
||||
.ValidateOnStart();
|
||||
|
||||
services.AddOptions<IdGeneratorOptions>()
|
||||
.Bind(configuration.GetSection(IdGeneratorOptions.SectionName))
|
||||
.ValidateDataAnnotations()
|
||||
.ValidateOnStart();
|
||||
|
||||
services.AddSingleton<IIdGenerator>(sp =>
|
||||
{
|
||||
var options = sp.GetRequiredService<Microsoft.Extensions.Options.IOptions<IdGeneratorOptions>>().Value;
|
||||
return new SnowflakeIdGenerator(options.WorkerId, options.DatacenterId);
|
||||
});
|
||||
|
||||
services.AddSingleton<IDatabaseConnectionFactory, DatabaseConnectionFactory>();
|
||||
services.AddScoped<IDapperExecutor, DapperExecutor>();
|
||||
return services;
|
||||
|
||||
@@ -3,15 +3,20 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using TakeoutSaaS.Shared.Abstractions.Entities;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Common.Persistence;
|
||||
|
||||
/// <summary>
|
||||
/// 应用基础 DbContext,统一处理审计字段、软删除与全局查询过滤。
|
||||
/// </summary>
|
||||
public abstract class AppDbContext(DbContextOptions options, ICurrentUserAccessor? currentUserAccessor = null) : DbContext(options)
|
||||
public abstract class AppDbContext(
|
||||
DbContextOptions options,
|
||||
ICurrentUserAccessor? currentUserAccessor = null,
|
||||
IIdGenerator? idGenerator = null) : DbContext(options)
|
||||
{
|
||||
private readonly ICurrentUserAccessor? _currentUserAccessor = currentUserAccessor;
|
||||
private readonly IIdGenerator? _idGenerator = idGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// 构建模型时应用软删除过滤器。
|
||||
@@ -50,10 +55,35 @@ public abstract class AppDbContext(DbContextOptions options, ICurrentUserAccesso
|
||||
/// </summary>
|
||||
protected virtual void OnBeforeSaving()
|
||||
{
|
||||
ApplyIdGeneration();
|
||||
ApplySoftDeleteMetadata();
|
||||
ApplyAuditMetadata();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为新增实体生成雪花 ID。
|
||||
/// </summary>
|
||||
private void ApplyIdGeneration()
|
||||
{
|
||||
if (_idGenerator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var entry in ChangeTracker.Entries<EntityBase>())
|
||||
{
|
||||
if (entry.State != EntityState.Added)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.Entity.Id == 0)
|
||||
{
|
||||
entry.Entity.Id = _idGenerator.NextId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将软删除实体的删除操作转换为设置 DeletedAt。
|
||||
/// </summary>
|
||||
@@ -114,10 +144,10 @@ public abstract class AppDbContext(DbContextOptions options, ICurrentUserAccesso
|
||||
}
|
||||
}
|
||||
|
||||
private Guid? GetCurrentUserIdOrNull()
|
||||
private long? GetCurrentUserIdOrNull()
|
||||
{
|
||||
var userId = _currentUserAccessor?.UserId ?? Guid.Empty;
|
||||
return userId == Guid.Empty ? null : userId;
|
||||
var userId = _currentUserAccessor?.UserId ?? 0;
|
||||
return userId == 0 ? null : userId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -141,12 +141,12 @@ internal abstract class DesignTimeDbContextFactoryBase<TContext> : IDesignTimeDb
|
||||
|
||||
private sealed class DesignTimeTenantProvider : ITenantProvider
|
||||
{
|
||||
public Guid GetCurrentTenantId() => Guid.Empty;
|
||||
public long GetCurrentTenantId() => 0;
|
||||
}
|
||||
|
||||
private sealed class DesignTimeCurrentUserAccessor : ICurrentUserAccessor
|
||||
{
|
||||
public Guid UserId => Guid.Empty;
|
||||
public long UserId => 0;
|
||||
public bool IsAuthenticated => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Shared.Abstractions.Entities;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Common.Persistence;
|
||||
|
||||
@@ -12,14 +13,15 @@ namespace TakeoutSaaS.Infrastructure.Common.Persistence;
|
||||
public abstract class TenantAwareDbContext(
|
||||
DbContextOptions options,
|
||||
ITenantProvider tenantProvider,
|
||||
ICurrentUserAccessor? currentUserAccessor = null) : AppDbContext(options, currentUserAccessor)
|
||||
ICurrentUserAccessor? currentUserAccessor = null,
|
||||
IIdGenerator? idGenerator = null) : AppDbContext(options, currentUserAccessor, idGenerator)
|
||||
{
|
||||
private readonly ITenantProvider _tenantProvider = tenantProvider ?? throw new ArgumentNullException(nameof(tenantProvider));
|
||||
|
||||
/// <summary>
|
||||
/// 当前请求租户 ID。
|
||||
/// </summary>
|
||||
protected Guid CurrentTenantId => _tenantProvider.GetCurrentTenantId();
|
||||
protected long CurrentTenantId => _tenantProvider.GetCurrentTenantId();
|
||||
|
||||
/// <summary>
|
||||
/// 保存前填充租户元数据并执行基础处理。
|
||||
@@ -71,7 +73,7 @@ public abstract class TenantAwareDbContext(
|
||||
|
||||
foreach (var entry in ChangeTracker.Entries<IMultiTenantEntity>())
|
||||
{
|
||||
if (entry.State == EntityState.Added && entry.Entity.TenantId == Guid.Empty && tenantId != Guid.Empty)
|
||||
if (entry.State == EntityState.Added && entry.Entity.TenantId == 0 && tenantId != 0)
|
||||
{
|
||||
entry.Entity.TenantId = tenantId;
|
||||
}
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
// <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("20251201042346_InitialDictionary")]
|
||||
partial class InitialDictionary
|
||||
{
|
||||
/// <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");
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("boolean")
|
||||
.HasDefaultValue(true);
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<int>("Scope")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("TenantId", "Code")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("dictionary_groups", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryItem", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("character varying(512)");
|
||||
|
||||
b.Property<Guid>("GroupId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<bool>("IsDefault")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("boolean")
|
||||
.HasDefaultValue(true);
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasDefaultValue(100);
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("GroupId", "Key")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("dictionary_items", (string)null);
|
||||
});
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialDictionary : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "dictionary_groups",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Code = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||
Scope = table.Column<int>(type: "integer", nullable: false),
|
||||
Description = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
|
||||
IsEnabled = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_dictionary_groups", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "dictionary_items",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
GroupId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Key = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
Value = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
IsDefault = table.Column<bool>(type: "boolean", nullable: false),
|
||||
IsEnabled = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true),
|
||||
SortOrder = table.Column<int>(type: "integer", nullable: false, defaultValue: 100),
|
||||
Description = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_dictionary_items", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_dictionary_items_dictionary_groups_GroupId",
|
||||
column: x => x.GroupId,
|
||||
principalTable: "dictionary_groups",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_dictionary_groups_TenantId",
|
||||
table: "dictionary_groups",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_dictionary_groups_TenantId_Code",
|
||||
table: "dictionary_groups",
|
||||
columns: new[] { "TenantId", "Code" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_dictionary_items_GroupId_Key",
|
||||
table: "dictionary_items",
|
||||
columns: new[] { "GroupId", "Key" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_dictionary_items_TenantId",
|
||||
table: "dictionary_items",
|
||||
column: "TenantId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "dictionary_items");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "dictionary_groups");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,599 +0,0 @@
|
||||
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: "实体唯一标识。");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using TakeoutSaaS.Domain.Dictionary.Entities;
|
||||
using TakeoutSaaS.Infrastructure.Common.Persistence;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
@@ -13,8 +14,9 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Persistence;
|
||||
public sealed class DictionaryDbContext(
|
||||
DbContextOptions<DictionaryDbContext> options,
|
||||
ITenantProvider tenantProvider,
|
||||
ICurrentUserAccessor? currentUserAccessor = null)
|
||||
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor)
|
||||
ICurrentUserAccessor? currentUserAccessor = null,
|
||||
IIdGenerator? idGenerator = null)
|
||||
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
|
||||
{
|
||||
/// <summary>
|
||||
/// 字典分组集。
|
||||
|
||||
@@ -19,7 +19,7 @@ public sealed class EfDictionaryRepository : IDictionaryRepository
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public Task<DictionaryGroup?> FindGroupByIdAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
public Task<DictionaryGroup?> FindGroupByIdAsync(long id, CancellationToken cancellationToken = default)
|
||||
=> _context.DictionaryGroups.FirstOrDefaultAsync(group => group.Id == id, cancellationToken);
|
||||
|
||||
public Task<DictionaryGroup?> FindGroupByCodeAsync(string code, CancellationToken cancellationToken = default)
|
||||
@@ -50,10 +50,10 @@ public sealed class EfDictionaryRepository : IDictionaryRepository
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<DictionaryItem?> FindItemByIdAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
public Task<DictionaryItem?> FindItemByIdAsync(long id, CancellationToken cancellationToken = default)
|
||||
=> _context.DictionaryItems.FirstOrDefaultAsync(item => item.Id == id, cancellationToken);
|
||||
|
||||
public async Task<IReadOnlyList<DictionaryItem>> GetItemsByGroupIdAsync(Guid groupId, CancellationToken cancellationToken = default)
|
||||
public async Task<IReadOnlyList<DictionaryItem>> GetItemsByGroupIdAsync(long groupId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await _context.DictionaryItems
|
||||
.AsNoTracking()
|
||||
@@ -77,7 +77,7 @@ public sealed class EfDictionaryRepository : IDictionaryRepository
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
=> _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
public async Task<IReadOnlyList<DictionaryItem>> GetItemsByCodesAsync(IEnumerable<string> codes, Guid tenantId, bool includeSystem, CancellationToken cancellationToken = default)
|
||||
public async Task<IReadOnlyList<DictionaryItem>> GetItemsByCodesAsync(IEnumerable<string> codes, long tenantId, bool includeSystem, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var normalizedCodes = codes
|
||||
.Where(code => !string.IsNullOrWhiteSpace(code))
|
||||
@@ -96,7 +96,7 @@ public sealed class EfDictionaryRepository : IDictionaryRepository
|
||||
.Include(item => item.Group)
|
||||
.Where(item => normalizedCodes.Contains(item.Group!.Code));
|
||||
|
||||
query = query.Where(item => item.TenantId == tenantId || (includeSystem && item.TenantId == Guid.Empty));
|
||||
query = query.Where(item => item.TenantId == tenantId || (includeSystem && item.TenantId == 0));
|
||||
|
||||
return await query
|
||||
.OrderBy(item => item.SortOrder)
|
||||
|
||||
@@ -22,7 +22,7 @@ public sealed class DistributedDictionaryCache : IDictionaryCache
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<DictionaryItemDto>?> GetAsync(Guid tenantId, string code, CancellationToken cancellationToken = default)
|
||||
public async Task<IReadOnlyList<DictionaryItemDto>?> GetAsync(long tenantId, string code, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var cacheKey = BuildKey(tenantId, code);
|
||||
var payload = await _cache.GetAsync(cacheKey, cancellationToken);
|
||||
@@ -34,7 +34,7 @@ public sealed class DistributedDictionaryCache : IDictionaryCache
|
||||
return JsonSerializer.Deserialize<List<DictionaryItemDto>>(payload, _serializerOptions);
|
||||
}
|
||||
|
||||
public Task SetAsync(Guid tenantId, string code, IReadOnlyList<DictionaryItemDto> items, CancellationToken cancellationToken = default)
|
||||
public Task SetAsync(long tenantId, string code, IReadOnlyList<DictionaryItemDto> items, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var cacheKey = BuildKey(tenantId, code);
|
||||
var payload = JsonSerializer.SerializeToUtf8Bytes(items, _serializerOptions);
|
||||
@@ -45,12 +45,12 @@ public sealed class DistributedDictionaryCache : IDictionaryCache
|
||||
return _cache.SetAsync(cacheKey, payload, options, cancellationToken);
|
||||
}
|
||||
|
||||
public Task RemoveAsync(Guid tenantId, string code, CancellationToken cancellationToken = default)
|
||||
public Task RemoveAsync(long tenantId, string code, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var cacheKey = BuildKey(tenantId, code);
|
||||
return _cache.RemoveAsync(cacheKey, cancellationToken);
|
||||
}
|
||||
|
||||
private static string BuildKey(Guid tenantId, string code)
|
||||
=> $"dictionary:{tenantId.ToString().ToLowerInvariant()}:{code.ToLowerInvariant()}";
|
||||
private static string BuildKey(long tenantId, string code)
|
||||
=> $"dictionary:{tenantId}:{code.ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
// <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("20251201042324_InitialIdentity")]
|
||||
partial class InitialIdentity
|
||||
{
|
||||
/// <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");
|
||||
|
||||
b.Property<string>("Account")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Avatar")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<Guid?>("MerchantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("Permissions")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("Roles")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("TenantId", "Account")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("identity_users", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.MiniUser", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Avatar")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("OpenId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("UnionId")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("TenantId", "OpenId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("mini_users", (string)null);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitialIdentity : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "identity_users",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Account = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
DisplayName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
PasswordHash = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false),
|
||||
MerchantId = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
Roles = table.Column<string>(type: "text", nullable: false),
|
||||
Permissions = table.Column<string>(type: "text", nullable: false),
|
||||
Avatar = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_identity_users", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "mini_users",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
OpenId = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false),
|
||||
UnionId = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||
Nickname = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
Avatar = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
UpdatedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
DeletedBy = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
TenantId = table.Column<Guid>(type: "uuid", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_mini_users", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_identity_users_TenantId",
|
||||
table: "identity_users",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_identity_users_TenantId_Account",
|
||||
table: "identity_users",
|
||||
columns: new[] { "TenantId", "Account" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_mini_users_TenantId",
|
||||
table: "mini_users",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_mini_users_TenantId_OpenId",
|
||||
table: "mini_users",
|
||||
columns: new[] { "TenantId", "OpenId" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "identity_users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "mini_users");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,581 +0,0 @@
|
||||
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: "实体唯一标识。");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,12 +39,12 @@ public sealed class SeedUserOptions
|
||||
/// <summary>
|
||||
/// 所属租户 ID。
|
||||
/// </summary>
|
||||
public Guid TenantId { get; set; }
|
||||
public long TenantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属商户 ID(平台管理员为空)。
|
||||
/// </summary>
|
||||
public Guid? MerchantId { get; set; }
|
||||
public long? MerchantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色集合。
|
||||
|
||||
@@ -22,6 +22,6 @@ public sealed class EfIdentityUserRepository : IIdentityUserRepository
|
||||
public Task<IdentityUser?> FindByAccountAsync(string account, CancellationToken cancellationToken = default)
|
||||
=> _dbContext.IdentityUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Account == account, cancellationToken);
|
||||
|
||||
public Task<IdentityUser?> FindByIdAsync(Guid userId, CancellationToken cancellationToken = default)
|
||||
public Task<IdentityUser?> FindByIdAsync(long userId, CancellationToken cancellationToken = default)
|
||||
=> _dbContext.IdentityUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Id == userId, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -22,17 +22,17 @@ public sealed class EfMiniUserRepository : IMiniUserRepository
|
||||
public Task<MiniUser?> FindByOpenIdAsync(string openId, CancellationToken cancellationToken = default)
|
||||
=> _dbContext.MiniUsers.AsNoTracking().FirstOrDefaultAsync(x => x.OpenId == openId, cancellationToken);
|
||||
|
||||
public Task<MiniUser?> FindByIdAsync(Guid id, CancellationToken cancellationToken = default)
|
||||
public Task<MiniUser?> FindByIdAsync(long id, CancellationToken cancellationToken = default)
|
||||
=> _dbContext.MiniUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
||||
|
||||
public async Task<MiniUser> CreateOrUpdateAsync(string openId, string? unionId, string? nickname, string? avatar, Guid tenantId, CancellationToken cancellationToken = default)
|
||||
public async Task<MiniUser> CreateOrUpdateAsync(string openId, string? unionId, string? nickname, string? avatar, long tenantId, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var user = await _dbContext.MiniUsers.FirstOrDefaultAsync(x => x.OpenId == openId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
user = new MiniUser
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = 0,
|
||||
OpenId = openId,
|
||||
UnionId = unionId,
|
||||
Nickname = nickname ?? "小程序用户",
|
||||
|
||||
@@ -42,7 +42,7 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
{
|
||||
user = new DomainIdentityUser
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = 0,
|
||||
Account = userOptions.Account,
|
||||
DisplayName = userOptions.DisplayName,
|
||||
TenantId = userOptions.TenantId,
|
||||
@@ -80,7 +80,7 @@ public sealed class IdentityDataSeeder(IServiceProvider serviceProvider, ILogger
|
||||
.Select(v => v.Trim())
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)];
|
||||
|
||||
private static IDisposable EnterTenantScope(ITenantContextAccessor accessor, Guid tenantId)
|
||||
private static IDisposable EnterTenantScope(ITenantContextAccessor accessor, long tenantId)
|
||||
{
|
||||
var previous = accessor.Current;
|
||||
accessor.Current = new TenantContext(tenantId, null, "admin-seed");
|
||||
|
||||
@@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using TakeoutSaaS.Domain.Identity.Entities;
|
||||
using TakeoutSaaS.Infrastructure.Common.Persistence;
|
||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
||||
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||
using TakeoutSaaS.Shared.Abstractions.Tenancy;
|
||||
|
||||
@@ -16,8 +17,9 @@ namespace TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
public sealed class IdentityDbContext(
|
||||
DbContextOptions<IdentityDbContext> options,
|
||||
ITenantProvider tenantProvider,
|
||||
ICurrentUserAccessor? currentUserAccessor = null)
|
||||
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor)
|
||||
ICurrentUserAccessor? currentUserAccessor = null,
|
||||
IIdGenerator? idGenerator = null)
|
||||
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
|
||||
{
|
||||
/// <summary>
|
||||
/// 管理后台用户集合。
|
||||
|
||||
@@ -26,7 +26,7 @@ public sealed class RedisRefreshTokenStore : IRefreshTokenStore
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
public async Task<RefreshTokenDescriptor> IssueAsync(Guid userId, DateTime expiresAt, CancellationToken cancellationToken = default)
|
||||
public async Task<RefreshTokenDescriptor> IssueAsync(long userId, DateTime expiresAt, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(48));
|
||||
var descriptor = new RefreshTokenDescriptor(token, userId, expiresAt, false);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,11 +9,11 @@ using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
namespace TakeoutSaaS.Infrastructure.Migrations.DictionaryDb
|
||||
{
|
||||
[DbContext(typeof(DictionaryDbContext))]
|
||||
[Migration("20251201094456_AddEntityComments")]
|
||||
partial class AddEntityComments
|
||||
[Migration("20251202005247_InitSnowflake_Dictionary")]
|
||||
partial class InitSnowflake_Dictionary
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
@@ -27,11 +27,13 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryGroup", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("实体唯一标识。");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
@@ -42,16 +44,16 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("创建时间(UTC)。");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("DeletedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||
|
||||
b.Property<string>("Description")
|
||||
@@ -75,16 +77,16 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
.HasColumnType("integer")
|
||||
.HasComment("分组作用域:系统/业务。");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("TenantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属租户 ID。");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("UpdatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.HasKey("Id");
|
||||
@@ -102,25 +104,27 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryItem", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("实体唯一标识。");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("创建时间(UTC)。");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("DeletedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||
|
||||
b.Property<string>("Description")
|
||||
@@ -128,8 +132,8 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
.HasColumnType("character varying(512)")
|
||||
.HasComment("描述信息。");
|
||||
|
||||
b.Property<Guid>("GroupId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("GroupId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("关联分组 ID。");
|
||||
|
||||
b.Property<bool>("IsDefault")
|
||||
@@ -154,16 +158,16 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
.HasDefaultValue(100)
|
||||
.HasComment("排序值,越小越靠前。");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("TenantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属租户 ID。");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("UpdatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<string>("Value")
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Migrations.DictionaryDb
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitSnowflake_Dictionary : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "dictionary_groups",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Code = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false, comment: "分组编码(唯一)。"),
|
||||
Name = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false, comment: "分组名称。"),
|
||||
Scope = table.Column<int>(type: "integer", nullable: false, comment: "分组作用域:系统/业务。"),
|
||||
Description = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true, comment: "描述信息。"),
|
||||
IsEnabled = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true, comment: "是否启用。"),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_dictionary_groups", x => x.Id);
|
||||
},
|
||||
comment: "参数字典分组(系统参数、业务参数)。");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "dictionary_items",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
GroupId = table.Column<long>(type: "bigint", nullable: false, comment: "关联分组 ID。"),
|
||||
Key = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false, comment: "字典项键。"),
|
||||
Value = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false, comment: "字典项值。"),
|
||||
IsDefault = table.Column<bool>(type: "boolean", nullable: false, comment: "是否默认项。"),
|
||||
IsEnabled = table.Column<bool>(type: "boolean", nullable: false, defaultValue: true, comment: "是否启用。"),
|
||||
SortOrder = table.Column<int>(type: "integer", nullable: false, defaultValue: 100, comment: "排序值,越小越靠前。"),
|
||||
Description = table.Column<string>(type: "character varying(512)", maxLength: 512, nullable: true, comment: "描述信息。"),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_dictionary_items", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_dictionary_items_dictionary_groups_GroupId",
|
||||
column: x => x.GroupId,
|
||||
principalTable: "dictionary_groups",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
},
|
||||
comment: "参数字典项。");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_dictionary_groups_TenantId",
|
||||
table: "dictionary_groups",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_dictionary_groups_TenantId_Code",
|
||||
table: "dictionary_groups",
|
||||
columns: new[] { "TenantId", "Code" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_dictionary_items_GroupId_Key",
|
||||
table: "dictionary_items",
|
||||
columns: new[] { "GroupId", "Key" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_dictionary_items_TenantId",
|
||||
table: "dictionary_items",
|
||||
column: "TenantId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "dictionary_items");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "dictionary_groups");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
namespace TakeoutSaaS.Infrastructure.Migrations.DictionaryDb
|
||||
{
|
||||
[DbContext(typeof(DictionaryDbContext))]
|
||||
partial class DictionaryDbContextModelSnapshot : ModelSnapshot
|
||||
@@ -24,11 +24,13 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryGroup", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("实体唯一标识。");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
@@ -39,16 +41,16 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("创建时间(UTC)。");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("DeletedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||
|
||||
b.Property<string>("Description")
|
||||
@@ -72,16 +74,16 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
.HasColumnType("integer")
|
||||
.HasComment("分组作用域:系统/业务。");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("TenantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属租户 ID。");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("UpdatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.HasKey("Id");
|
||||
@@ -99,25 +101,27 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Dictionary.Entities.DictionaryItem", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("实体唯一标识。");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("创建时间(UTC)。");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("DeletedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||
|
||||
b.Property<string>("Description")
|
||||
@@ -125,8 +129,8 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
.HasColumnType("character varying(512)")
|
||||
.HasComment("描述信息。");
|
||||
|
||||
b.Property<Guid>("GroupId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("GroupId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("关联分组 ID。");
|
||||
|
||||
b.Property<bool>("IsDefault")
|
||||
@@ -151,16 +155,16 @@ namespace TakeoutSaaS.Infrastructure.Dictionary.Migrations
|
||||
.HasDefaultValue(100)
|
||||
.HasComment("排序值,越小越靠前。");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("TenantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属租户 ID。");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("UpdatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<string>("Value")
|
||||
@@ -9,11 +9,11 @@ using TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
namespace TakeoutSaaS.Infrastructure.Migrations.IdentityDb
|
||||
{
|
||||
[DbContext(typeof(IdentityDbContext))]
|
||||
[Migration("20251201094410_AddEntityComments")]
|
||||
partial class AddEntityComments
|
||||
[Migration("20251202005226_InitSnowflake_Identity")]
|
||||
partial class InitSnowflake_Identity
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
@@ -27,11 +27,13 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.IdentityUser", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("实体唯一标识。");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("Account")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
@@ -47,16 +49,16 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("创建时间(UTC)。");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("DeletedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
@@ -65,8 +67,8 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("character varying(64)")
|
||||
.HasComment("展示名称。");
|
||||
|
||||
b.Property<Guid?>("MerchantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("MerchantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属商户(平台管理员为空)。");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
@@ -85,16 +87,16 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("text")
|
||||
.HasComment("角色集合。");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("TenantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属租户 ID。");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("UpdatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.HasKey("Id");
|
||||
@@ -112,11 +114,13 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.MiniUser", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("实体唯一标识。");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("Avatar")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
@@ -126,16 +130,16 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("创建时间(UTC)。");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("DeletedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
@@ -150,8 +154,8 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasComment("微信 OpenId。");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("TenantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属租户 ID。");
|
||||
|
||||
b.Property<string>("UnionId")
|
||||
@@ -163,8 +167,8 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("UpdatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.HasKey("Id");
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Migrations.IdentityDb
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class InitSnowflake_Identity : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "identity_users",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
Account = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false, comment: "登录账号。"),
|
||||
DisplayName = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false, comment: "展示名称。"),
|
||||
PasswordHash = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: false, comment: "密码哈希。"),
|
||||
MerchantId = table.Column<long>(type: "bigint", nullable: true, comment: "所属商户(平台管理员为空)。"),
|
||||
Roles = table.Column<string>(type: "text", nullable: false, comment: "角色集合。"),
|
||||
Permissions = table.Column<string>(type: "text", nullable: false, comment: "权限集合。"),
|
||||
Avatar = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true, comment: "头像地址。"),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_identity_users", x => x.Id);
|
||||
},
|
||||
comment: "管理后台账户实体(平台管理员、租户管理员或商户员工)。");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "mini_users",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false, comment: "实体唯一标识。")
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
OpenId = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: false, comment: "微信 OpenId。"),
|
||||
UnionId = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true, comment: "微信 UnionId,可能为空。"),
|
||||
Nickname = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false, comment: "昵称。"),
|
||||
Avatar = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true, comment: "头像地址。"),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "创建时间(UTC)。"),
|
||||
UpdatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "最近一次更新时间(UTC),从未更新时为 null。"),
|
||||
DeletedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: true, comment: "软删除时间(UTC),未删除时为 null。"),
|
||||
CreatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "创建人用户标识,匿名或系统操作时为 null。"),
|
||||
UpdatedBy = table.Column<long>(type: "bigint", nullable: true, comment: "最后更新人用户标识,匿名或系统操作时为 null。"),
|
||||
DeletedBy = table.Column<long>(type: "bigint", nullable: true, comment: "删除人用户标识(软删除),未删除时为 null。"),
|
||||
TenantId = table.Column<long>(type: "bigint", nullable: false, comment: "所属租户 ID。")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_mini_users", x => x.Id);
|
||||
},
|
||||
comment: "小程序用户实体。");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_identity_users_TenantId",
|
||||
table: "identity_users",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_identity_users_TenantId_Account",
|
||||
table: "identity_users",
|
||||
columns: new[] { "TenantId", "Account" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_mini_users_TenantId",
|
||||
table: "mini_users",
|
||||
column: "TenantId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_mini_users_TenantId_OpenId",
|
||||
table: "mini_users",
|
||||
columns: new[] { "TenantId", "OpenId" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "identity_users");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "mini_users");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using TakeoutSaaS.Infrastructure.Identity.Persistence;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
namespace TakeoutSaaS.Infrastructure.Migrations.IdentityDb
|
||||
{
|
||||
[DbContext(typeof(IdentityDbContext))]
|
||||
partial class IdentityDbContextModelSnapshot : ModelSnapshot
|
||||
@@ -24,11 +24,13 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.IdentityUser", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("实体唯一标识。");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("Account")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
@@ -44,16 +46,16 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("创建时间(UTC)。");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("DeletedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
@@ -62,8 +64,8 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("character varying(64)")
|
||||
.HasComment("展示名称。");
|
||||
|
||||
b.Property<Guid?>("MerchantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("MerchantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属商户(平台管理员为空)。");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
@@ -82,16 +84,16 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("text")
|
||||
.HasComment("角色集合。");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("TenantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属租户 ID。");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("UpdatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.HasKey("Id");
|
||||
@@ -109,11 +111,13 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
|
||||
modelBuilder.Entity("TakeoutSaaS.Domain.Identity.Entities.MiniUser", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("实体唯一标识。");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("Avatar")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)")
|
||||
@@ -123,16 +127,16 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("创建时间(UTC)。");
|
||||
|
||||
b.Property<Guid?>("CreatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("CreatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("创建人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.Property<DateTime?>("DeletedAt")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("软删除时间(UTC),未删除时为 null。");
|
||||
|
||||
b.Property<Guid?>("DeletedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("DeletedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("删除人用户标识(软删除),未删除时为 null。");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
@@ -147,8 +151,8 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("character varying(128)")
|
||||
.HasComment("微信 OpenId。");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long>("TenantId")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("所属租户 ID。");
|
||||
|
||||
b.Property<string>("UnionId")
|
||||
@@ -160,8 +164,8 @@ namespace TakeoutSaaS.Infrastructure.Identity.Migrations
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasComment("最近一次更新时间(UTC),从未更新时为 null。");
|
||||
|
||||
b.Property<Guid?>("UpdatedBy")
|
||||
.HasColumnType("uuid")
|
||||
b.Property<long?>("UpdatedBy")
|
||||
.HasColumnType("bigint")
|
||||
.HasComment("最后更新人用户标识,匿名或系统操作时为 null。");
|
||||
|
||||
b.HasKey("Id");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,5 +23,6 @@
|
||||
<ProjectReference Include="..\..\Domain\TakeoutSaaS.Domain\TakeoutSaaS.Domain.csproj" />
|
||||
<ProjectReference Include="..\..\Application\TakeoutSaaS.Application\TakeoutSaaS.Application.csproj" />
|
||||
<ProjectReference Include="..\..\Core\TakeoutSaaS.Shared.Abstractions\TakeoutSaaS.Shared.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\Core\TakeoutSaaS.Shared.Kernel\TakeoutSaaS.Shared.Kernel.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user