From 6401c37bc18e4a7cb7d3072668ebc141683d9fe9 Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Mon, 24 Dec 2018 16:29:52 +0300 Subject: [PATCH] Resolved #682: Automatically configure IHasExtraProperties for entities in EF Core. --- .../Abp/EntityFrameworkCore/AbpDbContext.cs | 69 +++++++++++++------ .../AbpEntityTypeBuilderExtensions.cs | 9 +++ .../TestApp/SecondContext/SecondDbContext.cs | 6 -- .../TestMigrationsDbContext.cs | 21 ------ .../EntityFrameworkCore/TestAppDbContext.cs | 16 ----- .../DocsDbContextModelBuilderExtensions.cs | 2 - 6 files changed, 58 insertions(+), 65 deletions(-) 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 6540930405..1f39d94774 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -11,6 +11,7 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; 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; @@ -49,10 +50,10 @@ namespace Volo.Abp.EntityFrameworkCore public ILogger> Logger { get; set; } - private static readonly MethodInfo ConfigureGlobalFiltersMethodInfo + private static readonly MethodInfo ConfigureBasePropertiesMethodInfo = typeof(AbpDbContext) .GetMethod( - nameof(ConfigureGlobalFilters), + nameof(ConfigureBaseProperties), BindingFlags.Instance | BindingFlags.NonPublic ); @@ -71,9 +72,7 @@ namespace Volo.Abp.EntityFrameworkCore foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { - ConfigureConcurrencyStamp(entityType); - - ConfigureGlobalFiltersMethodInfo + ConfigureBasePropertiesMethodInfo .MakeGenericMethod(entityType.ClrType) .Invoke(this, new object[] { modelBuilder, entityType }); } @@ -155,19 +154,6 @@ namespace Volo.Abp.EntityFrameworkCore } } - protected virtual void ConfigureConcurrencyStamp(IMutableEntityType entityType) - { - if (!typeof(IHasConcurrencyStamp).GetTypeInfo().IsAssignableFrom(entityType.ClrType)) - { - return; - } - - entityType - .GetProperties() - .First(p => p.Name == nameof(IHasConcurrencyStamp.ConcurrencyStamp)) - .IsConcurrencyToken = true; - } - protected virtual EntityChangeReport ApplyAbpConcepts() { var changeReport = new EntityChangeReport(); @@ -326,10 +312,53 @@ namespace Volo.Abp.EntityFrameworkCore AuditPropertySetter.SetDeletionProperties(entry.Entity); } - protected void ConfigureGlobalFilters(ModelBuilder modelBuilder, IMutableEntityType entityType) + protected virtual void ConfigureBaseProperties(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) + where TEntity : class + { + ConfigureConcurrencyStamp(modelBuilder, mutableEntityType); + ConfigureExtraProperties(modelBuilder, mutableEntityType); + ConfigureGlobalFilters(modelBuilder, mutableEntityType); + } + + protected virtual void ConfigureConcurrencyStamp(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) + where TEntity : class + { + if (!typeof(IHasConcurrencyStamp).GetTypeInfo().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).GetTypeInfo().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 ConfigureGlobalFilters(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) where TEntity : class { - if (entityType.BaseType == null && ShouldFilterEntity(entityType)) + if (mutableEntityType.BaseType == null && ShouldFilterEntity(mutableEntityType)) { var filterExpression = CreateFilterExpression(); if (filterExpression != null) 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 143dd07e30..200e7a707c 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 @@ -4,12 +4,21 @@ using Microsoft.EntityFrameworkCore.Metadata.Builders; using Newtonsoft.Json; using Volo.Abp.Auditing; using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; using Volo.Abp.MultiTenancy; namespace Volo.Abp.EntityFrameworkCore.Modeling { public static class AbpEntityTypeBuilderExtensions { + public static void ConfigureConcurrencyStamp(this EntityTypeBuilder b) + where T : class, IHasConcurrencyStamp + { + b.Property(x => x.ConcurrencyStamp) + .IsConcurrencyToken() + .HasColumnName(nameof(IHasConcurrencyStamp.ConcurrencyStamp)); + } + public static void ConfigureExtraProperties(this EntityTypeBuilder b) where T : class, IHasExtraProperties { diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/SecondDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/SecondDbContext.cs index bb2f0504ad..9b584a494c 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/SecondDbContext.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/SecondDbContext.cs @@ -21,12 +21,6 @@ namespace Volo.Abp.EntityFrameworkCore.TestApp.SecondContext modelBuilder.Entity(b => { b.HasKey(p => new { p.PersonId, p.Number }); - b.ConfigureExtraProperties(); - }); - - modelBuilder.Entity(b => - { - b.ConfigureExtraProperties(); }); } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs index 68e6ac97cb..cb9726d6b4 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.EntityFrameworkCore.TestApp.SecondContext; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; using Volo.Abp.TestApp.Domain; @@ -30,26 +29,6 @@ namespace Volo.Abp.EntityFrameworkCore { b.HasKey(p => new { p.PersonId, p.Number }); }); - - modelBuilder.Entity(b => - { - b.ConfigureExtraProperties(); - }); - - modelBuilder.Entity(b => - { - b.ConfigureExtraProperties(); - }); - - modelBuilder.Entity(b => - { - b.ConfigureExtraProperties(); - }); - - modelBuilder.Entity(b => - { - b.ConfigureExtraProperties(); - }); } } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs index bef7830567..00e052d2dd 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs @@ -1,6 +1,5 @@ using Microsoft.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; using Volo.Abp.TestApp.Domain; @@ -24,25 +23,10 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore { base.OnModelCreating(modelBuilder); - modelBuilder.Entity(b => - { - b.ConfigureExtraProperties(); - }); - modelBuilder.Entity(b => { b.HasKey(p => new {p.PersonId, p.Number}); }); - - modelBuilder.Entity(b => - { - b.ConfigureExtraProperties(); - }); - - modelBuilder.Entity(b => - { - b.ConfigureExtraProperties(); - }); } } } diff --git a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs index 1235bf5fb2..20e169f279 100644 --- a/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs +++ b/modules/docs/src/Volo.Docs.EntityFrameworkCore/Volo/Docs/EntityFrameworkCore/DocsDbContextModelBuilderExtensions.cs @@ -29,8 +29,6 @@ namespace Volo.Docs.EntityFrameworkCore b.Property(x => x.DefaultDocumentName).IsRequired().HasMaxLength(ProjectConsts.MaxDefaultDocumentNameLength); b.Property(x => x.NavigationDocumentName).IsRequired().HasMaxLength(ProjectConsts.MaxNavigationDocumentNameLength); b.Property(x => x.LatestVersionBranchName).HasMaxLength(ProjectConsts.MaxLatestVersionBranchNameLength); - - b.ConfigureExtraProperties(); }); } }