diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs index 18758d98e38..c911c7f4611 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -11,13 +11,13 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Newtonsoft.Json; using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities.Events; using Volo.Abp.EntityFrameworkCore.EntityHistory; +using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.Guids; using Volo.Abp.MultiTenancy; @@ -352,147 +352,9 @@ protected virtual void ConfigureBaseProperties(ModelBuilder modelBuilde return; } - ConfigureConcurrencyStampProperty(modelBuilder, mutableEntityType); - ConfigureExtraProperties(modelBuilder, mutableEntityType); - ConfigureAuditProperties(modelBuilder, mutableEntityType); - ConfigureTenantIdProperty(modelBuilder, mutableEntityType); - ConfigureGlobalFilters(modelBuilder, mutableEntityType); - } - - protected virtual void ConfigureConcurrencyStampProperty(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) - where TEntity : class - { - if (!typeof(IHasConcurrencyStamp).IsAssignableFrom(typeof(TEntity))) - { - return; - } - - modelBuilder.Entity(b => - { - b.Property(x => ((IHasConcurrencyStamp) x).ConcurrencyStamp) - .IsConcurrencyToken() - .HasColumnName(nameof(IHasConcurrencyStamp.ConcurrencyStamp)); - }); - } - - protected virtual void ConfigureExtraProperties(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) - where TEntity : class - { - if (!typeof(IHasExtraProperties).IsAssignableFrom(typeof(TEntity))) - { - return; - } - - modelBuilder.Entity(b => - { - b.Property(x => ((IHasExtraProperties) x).ExtraProperties) - .HasConversion( - d => JsonConvert.SerializeObject(d, Formatting.None), - s => JsonConvert.DeserializeObject>(s) - ) - .HasColumnName(nameof(IHasExtraProperties.ExtraProperties)); - }); - } - - protected virtual void ConfigureAuditProperties(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) - where TEntity : class - { - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IHasCreationTime)x).CreationTime) - .IsRequired() - .HasColumnName(nameof(IHasCreationTime.CreationTime)); - }); - } + modelBuilder.Entity().ConfigureByConvention(); - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IMayHaveCreator)x).CreatorId) - .IsRequired(false) - .HasColumnName(nameof(IMayHaveCreator.CreatorId)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IMustHaveCreator)x).CreatorId) - .IsRequired() - .HasColumnName(nameof(IMustHaveCreator.CreatorId)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IHasModificationTime)x).LastModificationTime) - .IsRequired(false) - .HasColumnName(nameof(IHasModificationTime.LastModificationTime)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IModificationAuditedObject)x).LastModifierId) - .IsRequired(false) - .HasColumnName(nameof(IModificationAuditedObject.LastModifierId)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((ISoftDelete) x).IsDeleted) - .IsRequired() - .HasDefaultValue(false) - .HasColumnName(nameof(ISoftDelete.IsDeleted)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IHasDeletionTime)x).DeletionTime) - .IsRequired(false) - .HasColumnName(nameof(IHasDeletionTime.DeletionTime)); - }); - } - - if (typeof(TEntity).IsAssignableTo()) - { - modelBuilder.Entity(b => - { - b.Property(x => ((IDeletionAuditedObject)x).DeleterId) - .IsRequired(false) - .HasColumnName(nameof(IDeletionAuditedObject.DeleterId)); - }); - } - } - - protected virtual void ConfigureTenantIdProperty(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) - where TEntity : class - { - if (!typeof(TEntity).IsAssignableTo()) - { - return; - } - - modelBuilder.Entity(b => - { - b.Property(x => ((IMultiTenant)x).TenantId) - .IsRequired(false) - .HasColumnName(nameof(IMultiTenant.TenantId)); - }); + ConfigureGlobalFilters(modelBuilder, mutableEntityType); } protected virtual void ConfigureGlobalFilters(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs index 132e91c079f..dceaeaf74fc 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/Modeling/AbpEntityTypeBuilderExtensions.cs @@ -2,11 +2,11 @@ using System.Collections.Generic; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Newtonsoft.Json; using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.Domain.Entities; -using Volo.Abp.Domain.Entities.Auditing; +using Volo.Abp.EntityFrameworkCore.ValueComparers; +using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.MultiTenancy; namespace Volo.Abp.EntityFrameworkCore.Modeling @@ -57,11 +57,9 @@ public static void TryConfigureExtraProperties(this EntityTypeBuilder b) if (b.Metadata.ClrType.IsAssignableTo()) { b.Property>(nameof(IHasExtraProperties.ExtraProperties)) - .HasConversion( - d => JsonConvert.SerializeObject(d, Formatting.None), - s => JsonConvert.DeserializeObject>(s) - ) - .HasColumnName(nameof(IHasExtraProperties.ExtraProperties)); + .HasColumnName(nameof(IHasExtraProperties.ExtraProperties)) + .HasConversion(new AbpJsonValueConverter>()) + .Metadata.SetValueComparer(new AbpDictionaryValueComparer()); } } diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/AbpDictionaryValueComparer.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/AbpDictionaryValueComparer.cs new file mode 100644 index 00000000000..4efd8bfa636 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueComparers/AbpDictionaryValueComparer.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.EntityFrameworkCore.ChangeTracking; + +namespace Volo.Abp.EntityFrameworkCore.ValueComparers +{ + public class AbpDictionaryValueComparer : ValueComparer> + { + public AbpDictionaryValueComparer() + : base( + (d1, d2) => d1.SequenceEqual(d2), + d => d.Aggregate(0, (k, v) => HashCode.Combine(k, v.GetHashCode())), + d => d.ToDictionary(k => k.Key, v => v.Value)) + { + } + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs new file mode 100644 index 00000000000..e77b2842a84 --- /dev/null +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/ValueConverters/AbpJsonValueConverter.cs @@ -0,0 +1,15 @@ +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Newtonsoft.Json; + +namespace Volo.Abp.EntityFrameworkCore.ValueConverters +{ + public class AbpJsonValueConverter : ValueConverter + { + public AbpJsonValueConverter() + : base( + d => JsonConvert.SerializeObject(d, Formatting.None), + s => JsonConvert.DeserializeObject(s)) + { + } + } +} diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs index bd69f6948fb..33e2b011c48 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/EntityFrameworkCore/IdentityServerDbContextModelCreatingExtensions.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; using Microsoft.EntityFrameworkCore; -using Newtonsoft.Json; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.Modeling; +using Volo.Abp.EntityFrameworkCore.ValueComparers; +using Volo.Abp.EntityFrameworkCore.ValueConverters; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; using Volo.Abp.IdentityServer.Grants; @@ -202,10 +203,8 @@ public static void ConfigureIdentityServer( identityResource.Property(x => x.DisplayName).HasMaxLength(IdentityResourceConsts.DisplayNameMaxLength); identityResource.Property(x => x.Description).HasMaxLength(IdentityResourceConsts.DescriptionMaxLength); identityResource.Property(x => x.Properties) - .HasConversion( - d => JsonConvert.SerializeObject(d, Formatting.None), - s => JsonConvert.DeserializeObject>(s) - ); + .HasConversion(new AbpJsonValueConverter>()) + .Metadata.SetValueComparer(new AbpDictionaryValueComparer()); identityResource.HasMany(x => x.UserClaims).WithOne().HasForeignKey(x => x.IdentityResourceId).IsRequired(); }); @@ -229,10 +228,8 @@ public static void ConfigureIdentityServer( apiResource.Property(x => x.DisplayName).HasMaxLength(ApiResourceConsts.DisplayNameMaxLength); apiResource.Property(x => x.Description).HasMaxLength(ApiResourceConsts.DescriptionMaxLength); apiResource.Property(x => x.Properties) - .HasConversion( - d => JsonConvert.SerializeObject(d, Formatting.None), - s => JsonConvert.DeserializeObject>(s) - ); + .HasConversion(new AbpJsonValueConverter>()) + .Metadata.SetValueComparer(new AbpDictionaryValueComparer()); apiResource.HasMany(x => x.Secrets).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired(); apiResource.HasMany(x => x.Scopes).WithOne().HasForeignKey(x => x.ApiResourceId).IsRequired();