#nullable enable using Abp.Domain.Entities; using Abp.EntityFrameworkCore; using Abp.Notifications; using Abp.Webhooks; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata; using System.ComponentModel.DataAnnotations.Schema; using System.Reflection; using VberZero.BaseSystem; using VberZero.BaseSystem.Organizations; using VberZero.BaseSystem.Roles; using VberZero.BaseSystem.Users; using VberZero.EntityHistory; namespace VberZero.EntityFramework; public abstract class VzCommonDbContext : AbpDbContext where TSelf : VzCommonDbContext { public virtual DbSet Roles { get; set; } public virtual DbSet Users { get; set; } public virtual DbSet SysFunctions { get; set; } public virtual DbSet SysHelps { get; set; } public virtual DbSet SysAttaches { get; set; } public virtual DbSet SysStates { get; set; } public virtual DbSet SysCalendars { get; set; } public virtual DbSet SysAutoCompleteQueries { get; set; } public virtual DbSet SysSettings { get; set; } public virtual DbSet UserLogins { get; set; } public virtual DbSet UserLoginAttempts { get; set; } public virtual DbSet UserRoles { get; set; } public virtual DbSet UserClaims { get; set; } public virtual DbSet UserTokens { get; set; } public virtual DbSet RoleClaims { get; set; } public virtual DbSet Permissions { get; set; } public virtual DbSet RolePermissions { get; set; } public virtual DbSet UserPermissions { get; set; } public virtual DbSet AuditLogs { get; set; } public virtual DbSet OrganizationUnits { get; set; } public virtual DbSet UserOrganizationUnits { get; set; } public virtual DbSet OrganizationUnitRoles { get; set; } public virtual DbSet TenantNotifications { get; set; } public virtual DbSet UserNotifications { get; set; } public virtual DbSet NotificationSubscriptions { get; set; } public virtual DbSet WebhookEvents { get; set; } public virtual DbSet WebhookSubscriptions { get; set; } public virtual DbSet WebhookSendAttempts { get; set; } //public virtual DbSet EntityChanges { get; set; } //public virtual DbSet EntityChangeSets { get; set; } //public virtual DbSet EntityPropertyChanges { get; set; } //public virtual DbSet Languages { get; set; } //public virtual DbSet LanguageTexts { get; set; } //public virtual DbSet DynamicProperties { get; set; } //public virtual DbSet DynamicPropertyValues { get; set; } //public virtual DbSet DynamicEntityProperties { get; set; } //public virtual DbSet DynamicEntityPropertyValues { get; set; } public IEntityHistoryHelper EntityHistoryHelper { get; set; } /// /// /// /// protected VzCommonDbContext(DbContextOptions options) : base(options) { } public override int SaveChanges() { //var changeSet = EntityHistoryHelper.CreateEntityChangeSet(ChangeTracker.Entries().ToList()); var result = base.SaveChanges(); //EntityHistoryHelper.Save(changeSet); return result; } public override async Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)) { //var changeSet = EntityHistoryHelper.CreateEntityChangeSet(ChangeTracker.Entries().ToList()); var result = await base.SaveChangesAsync(cancellationToken); //if (EntityHistoryHelper != null) //{ // await EntityHistoryHelper.SaveAsync(changeSet); //} return result; } protected override void OnModelCreating(ModelBuilder modelBuilder) { //base.OnModelCreating(modelBuilder); //取消删除级联 SetForeignKeyDeleteBehaviors(modelBuilder); //全局配置 foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { ConfigureGlobalFiltersMethodInfo?.MakeGenericMethod(entityType.ClrType) .Invoke(this, new object[] { modelBuilder, entityType }); ConfigureGlobalValueConverterMethodInfo?.MakeGenericMethod(entityType.ClrType) .Invoke(this, new object[] { modelBuilder, entityType }); } modelBuilder.Entity(b => { b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken(); b.HasOne(p => p.DeleterUser) .WithMany() .HasForeignKey(p => p.DeleterUserId).OnDelete(DeleteBehavior.Restrict); b.HasOne(p => p.CreatorUser) .WithMany() .HasForeignKey(p => p.CreatorUserId).OnDelete(DeleteBehavior.Restrict); b.HasOne(p => p.LastModifierUser) .WithMany() .HasForeignKey(p => p.LastModifierUserId).OnDelete(DeleteBehavior.Restrict); b.HasIndex(e => new { e.TenantId, e.NormalizedUserName }); b.HasIndex(e => new { e.TenantId, e.NormalizedEmailAddress }); }); modelBuilder.Entity(b => { b.Property(r => r.ConcurrencyStamp).IsConcurrencyToken(); b.HasIndex(e => new { e.TenantId, e.NormalizedName }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.UserId }); b.HasIndex(e => new { e.TenantId, e.ExecutionTime }); b.HasIndex(e => new { e.TenantId, e.ExecutionDuration }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.NotificationName, e.EntityTypeName, e.EntityId, e.UserId }); b.HasIndex(e => new { e.TenantId, e.NotificationName, e.EntityTypeName, e.EntityId, e.UserId }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.Code }).IsUnique(false); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.Name }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.RoleId }); b.HasIndex(e => new { e.TenantId, e.ClaimType }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.Name, e.UserId }).IsUnique().HasFilter(null); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.ClaimType }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenancyName, e.UserNameOrEmailOrPhone, e.Result }); b.HasIndex(ula => new { ula.UserId, ula.TenantId }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.LoginProvider, e.ProviderKey }); b.HasIndex(e => new { e.TenantId, e.UserId }); b.HasIndex(e => new { e.ProviderKey, e.TenantId }).IsUnique(); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.UserId, e.State, e.CreationTime }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.UserId }); b.HasIndex(e => new { e.TenantId, e.OrganizationUnitId }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.RoleId }); b.HasIndex(e => new { e.TenantId, e.OrganizationUnitId }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.UserId }); b.HasIndex(e => new { e.TenantId, e.RoleId }); }); modelBuilder.Entity(b => { b.HasIndex(e => new { e.TenantId, e.UserId }); }); //modelBuilder.Entity(b => //{ // b.HasIndex(e => new { e.PropertyName, e.TenantId }).IsUnique(); //}); //modelBuilder.Entity(b => //{ // b.HasIndex(e => new { e.EntityFullName, e.DynamicPropertyId, e.TenantId }).IsUnique(); //}); //modelBuilder.Entity(b => //{ // b.HasIndex(e => new { e.TenantId, e.Name }); //}); //modelBuilder.Entity(b => //{ // b.HasIndex(e => new { e.TenantId, e.Source, e.LanguageName, e.Key }); //}); //modelBuilder.Entity(b => //{ // b.HasMany(p => p.PropertyChanges) // .WithOne() // .HasForeignKey(p => p.EntityChangeId); // b.HasIndex(e => new { e.EntityChangeSetId }); // b.HasIndex(e => new { e.EntityTypeFullName, e.EntityId }); //}); //modelBuilder.Entity(b => //{ // b.HasMany(p => p.EntityChanges) // .WithOne() // .HasForeignKey(p => p.EntityChangeSetId); // b.HasIndex(e => new { e.TenantId, e.UserId }); // b.HasIndex(e => new { e.TenantId, e.CreationTime }); // b.HasIndex(e => new { e.TenantId, e.Reason }); //}); //modelBuilder.Entity(b => //{ // b.HasIndex(e => e.EntityChangeId); //}); } private static readonly MethodInfo? ConfigureGlobalFiltersMethodInfo = typeof(VzCommonDbContext).GetMethod(nameof(ConfigureGlobalFilters), BindingFlags.Instance | BindingFlags.NonPublic); private static readonly MethodInfo? ConfigureGlobalValueConverterMethodInfo = typeof(VzCommonDbContext).GetMethod(nameof(VzConfigureGlobalValueConverter), BindingFlags.Instance | BindingFlags.NonPublic); /// /// 全局配置 /// /// /// /// protected void VzConfigureGlobalValueConverter(ModelBuilder modelBuilder, IMutableEntityType entityType) where TEntity : class { ConfigureGlobalValueConverter(modelBuilder, entityType); if (entityType.BaseType == null && !typeof(TEntity).IsDefined(typeof(OwnedAttribute), true) && !entityType.IsOwned()) { if (typeof(IEntity).IsAssignableFrom(typeof(TEntity))) { //Console.WriteLine(typeof(TEntity).Name); //定义主键为string的长度 modelBuilder .Entity() .Property("Id").HasMaxLength(VzConsts.PrimaryKey); } //定义外键为string的长度 var propertyInfos = typeof(TEntity).GetProperties(); foreach (var info in propertyInfos) { var name = info.GetCustomAttribute()?.Name; //Console.WriteLine(typeof(TEntity).Name + "====>" + info.Name + "====>" + name); if (name != null && typeof(TEntity).GetProperty(name)?.PropertyType == typeof(string)) { //Console.WriteLine("YYYY"); modelBuilder .Entity() .Property(name).HasMaxLength(VzConsts.PrimaryKey); Console.WriteLine(typeof(TEntity).Name + "====>" + info.Name + "====>" + name + "====>长度设为" + VzConsts.PrimaryKey); } } var userId = propertyInfos.FirstOrDefault(a => a.Name == "UserId"); var tenantId = propertyInfos.FirstOrDefault(a => a.Name == "TenantId"); if (userId != null && tenantId != null) { modelBuilder .Entity().HasIndex("UserId", "TenantId"); } else if (userId != null) { modelBuilder .Entity().HasIndex("UserId"); } else if (tenantId != null) { modelBuilder .Entity().HasIndex("TenantId"); } } } /// /// 取消级联删除 /// /// protected virtual void SetForeignKeyDeleteBehaviors(ModelBuilder modelBuilder) { var foreignKeys = modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()).Where(fk => fk.DeleteBehavior == DeleteBehavior.Cascade); foreach (var fk in foreignKeys) { fk.DeleteBehavior = DeleteBehavior.Restrict; } } }