diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs index cd85acce50..1d058d19b9 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs @@ -43,6 +43,13 @@ public abstract class BasicRepositoryBase : public IEntityChangeTrackingProvider EntityChangeTrackingProvider => LazyServiceProvider.LazyGetRequiredService(); public bool? IsChangeTrackingEnabled { get; protected set; } + + protected string? CustomEntityName { get; private set; } + + public void SetCustomEntityName(string? name) + { + CustomEntityName = name; + } protected BasicRepositoryBase() { diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs index dc39255b25..c5942088f0 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs @@ -13,6 +13,8 @@ namespace Volo.Abp.Domain.Repositories; public interface IRepository { bool? IsChangeTrackingEnabled { get; } + + void SetCustomEntityName(string? name); } public interface IRepository : IReadOnlyRepository, IBasicRepository diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs index 0ed9a2e199..760660dc82 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs @@ -61,7 +61,7 @@ public class EfCoreRepository : RepositoryBase, IE } [Obsolete("Use GetDbSetAsync() method.")] - public virtual DbSet DbSet => DbContext.Set(); + public virtual DbSet DbSet => GetDbSetInternal(DbContext); Task> IEfCoreRepository.GetDbSetAsync() { @@ -70,7 +70,7 @@ public class EfCoreRepository : RepositoryBase, IE protected async Task> GetDbSetAsync() { - return (await GetDbContextAsync()).Set(); + return GetDbSetInternal(await GetDbContextAsync()); } protected async Task GetDbConnectionAsync() @@ -110,7 +110,7 @@ public class EfCoreRepository : RepositoryBase, IE var dbContext = await GetDbContextAsync(); - var savedEntity = (await dbContext.Set().AddAsync(entity, GetCancellationToken(cancellationToken))).Entity; + var savedEntity = (await GetDbSetInternal(dbContext).AddAsync(entity, GetCancellationToken(cancellationToken))).Entity; if (autoSave) { @@ -120,6 +120,13 @@ public class EfCoreRepository : RepositoryBase, IE return savedEntity; } + private DbSet GetDbSetInternal(TDbContext dbContext) + { + return CustomEntityName != null + ? dbContext.Set(CustomEntityName) + : dbContext.Set(); + } + public async override Task InsertManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { var entityArray = entities.ToArray(); @@ -147,7 +154,7 @@ public class EfCoreRepository : RepositoryBase, IE return; } - await dbContext.Set().AddRangeAsync(entityArray, cancellationToken); + await GetDbSetInternal(dbContext).AddRangeAsync(entityArray, cancellationToken); if (autoSave) { @@ -159,9 +166,10 @@ public class EfCoreRepository : RepositoryBase, IE { var dbContext = await GetDbContextAsync(); - if (dbContext.Set().Local.All(e => e != entity)) + var dbSet = GetDbSetInternal(dbContext); + if (dbSet.Local.All(e => e != entity)) { - dbContext.Set().Attach(entity); + dbSet.Attach(entity); dbContext.Update(entity); } @@ -197,7 +205,7 @@ public class EfCoreRepository : RepositoryBase, IE var dbContext = await GetDbContextAsync(); - dbContext.Set().UpdateRange(entityArray); + GetDbSetInternal(dbContext).UpdateRange(entityArray); if (autoSave) { @@ -209,7 +217,7 @@ public class EfCoreRepository : RepositoryBase, IE { var dbContext = await GetDbContextAsync(); - dbContext.Set().Remove(entity); + GetDbSetInternal(dbContext).Remove(entity); if (autoSave) { @@ -318,7 +326,7 @@ public class EfCoreRepository : RepositoryBase, IE public async override Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) { var dbContext = await GetDbContextAsync(); - var dbSet = dbContext.Set(); + var dbSet = GetDbSetInternal(dbContext); var entities = await dbSet .Where(predicate) @@ -335,8 +343,9 @@ public class EfCoreRepository : RepositoryBase, IE public async override Task DeleteDirectAsync(Expression> predicate, CancellationToken cancellationToken = default) { var dbContext = await GetDbContextAsync(); - var dbSet = dbContext.Set(); - await dbSet.Where(predicate).ExecuteDeleteAsync(GetCancellationToken(cancellationToken)); + await GetDbSetInternal(dbContext) + .Where(predicate) + .ExecuteDeleteAsync(GetCancellationToken(cancellationToken)); } public virtual async Task EnsureCollectionLoadedAsync( 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 797e4dbb67..fceb338051 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs @@ -37,6 +37,7 @@ using Volo.Abp.Reflection; using Volo.Abp.Timing; using Volo.Abp.Uow; using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace Volo.Abp.EntityFrameworkCore; @@ -126,17 +127,7 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, foreach (var entityType in modelBuilder.Model.GetEntityTypes().ToArray()) { - ConfigureBasePropertiesMethodInfo - .MakeGenericMethod(entityType.ClrType) - .Invoke(this, new object[] { modelBuilder, entityType }); - - ConfigureValueConverterMethodInfo - .MakeGenericMethod(entityType.ClrType) - .Invoke(this, new object[] { modelBuilder, entityType }); - - ConfigureValueGeneratedMethodInfo - .MakeGenericMethod(entityType.ClrType) - .Invoke(this, new object[] { modelBuilder, entityType }); + ConfigureEntityTypeProperties(modelBuilder, entityType); } if (LazyServiceProvider == null || Options == null) @@ -151,6 +142,23 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, } } + protected virtual void ConfigureEntityTypeProperties( + ModelBuilder modelBuilder, + IMutableEntityType entityType) + { + ConfigureBasePropertiesMethodInfo + .MakeGenericMethod(entityType.ClrType) + .Invoke(this, new object[] { modelBuilder, entityType }); + + ConfigureValueConverterMethodInfo + .MakeGenericMethod(entityType.ClrType) + .Invoke(this, new object[] { modelBuilder, entityType }); + + ConfigureValueGeneratedMethodInfo + .MakeGenericMethod(entityType.ClrType) + .Invoke(this, new object[] { modelBuilder, entityType }); + } + protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { base.ConfigureConventions(configurationBuilder); @@ -762,7 +770,9 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, AuditPropertySetter?.IncrementEntityVersionProperty(entry.Entity); } - protected virtual void ConfigureBaseProperties(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) + protected virtual void ConfigureBaseProperties( + ModelBuilder modelBuilder, + IMutableEntityType mutableEntityType) where TEntity : class { if (mutableEntityType.IsOwned()) @@ -775,25 +785,44 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, return; } - modelBuilder.Entity().ConfigureByConvention(); + var entityTypeBuilder = CreateEntityTypeBuilderFromMutableEntityType( + modelBuilder, + mutableEntityType + ); + + entityTypeBuilder.ConfigureByConvention(); + + ConfigureGlobalFilters(modelBuilder, mutableEntityType, entityTypeBuilder); + } - ConfigureGlobalFilters(modelBuilder, mutableEntityType); + protected virtual EntityTypeBuilder CreateEntityTypeBuilderFromMutableEntityType( + ModelBuilder modelBuilder, + IMutableEntityType mutableEntityType) where TEntity : class + { + return mutableEntityType.HasSharedClrType + ? modelBuilder.SharedTypeEntity(mutableEntityType.Name) + : modelBuilder.Entity(); } - protected virtual void ConfigureGlobalFilters(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) + protected virtual void ConfigureGlobalFilters( + ModelBuilder modelBuilder, + IMutableEntityType mutableEntityType, + EntityTypeBuilder entityTypeBuilder) where TEntity : class { if (mutableEntityType.BaseType == null && ShouldFilterEntity(mutableEntityType)) { - var filterExpression = CreateFilterExpression(modelBuilder); + var filterExpression = CreateFilterExpression(modelBuilder, entityTypeBuilder); if (filterExpression != null) { - modelBuilder.Entity().HasAbpQueryFilter(filterExpression); + entityTypeBuilder.HasAbpQueryFilter(filterExpression); } } } - protected virtual void ConfigureValueConverter(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) + protected virtual void ConfigureValueConverter( + ModelBuilder modelBuilder, + IMutableEntityType mutableEntityType) where TEntity : class { if (mutableEntityType.BaseType != null || @@ -808,6 +837,7 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, { return; } + foreach (var property in mutableEntityType.GetProperties(). Where(property => property.PropertyInfo != null && @@ -815,8 +845,12 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, property.PropertyInfo.CanWrite && ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault(property.PropertyInfo) == null)) { - modelBuilder - .Entity() + var entityTypeBuilder = CreateEntityTypeBuilderFromMutableEntityType( + modelBuilder, + mutableEntityType + ); + + entityTypeBuilder .Property(property.Name) .HasConversion(property.ClrType == typeof(DateTime) ? new AbpDateTimeValueConverter(Clock) @@ -824,7 +858,9 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, } } - protected virtual void ConfigureValueGenerated(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType) + protected virtual void ConfigureValueGenerated( + ModelBuilder modelBuilder, + IMutableEntityType mutableEntityType) where TEntity : class { if (!typeof(IEntity).IsAssignableFrom(typeof(TEntity))) @@ -832,7 +868,8 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, return; } - var idPropertyBuilder = modelBuilder.Entity().Property(x => ((IEntity)x).Id); + var entityTypeBuilder = CreateEntityTypeBuilderFromMutableEntityType(modelBuilder, mutableEntityType); + var idPropertyBuilder = entityTypeBuilder.Property(x => ((IEntity)x).Id); if (idPropertyBuilder.Metadata.PropertyInfo!.IsDefined(typeof(DatabaseGeneratedAttribute), true)) { return; @@ -856,25 +893,30 @@ public abstract class AbpDbContext : DbContext, IAbpEfCoreDbContext, return false; } - protected virtual Expression>? CreateFilterExpression(ModelBuilder modelBuilder) + protected virtual Expression>? CreateFilterExpression( + ModelBuilder modelBuilder, + EntityTypeBuilder entityTypeBuilder) where TEntity : class { Expression>? expression = null; if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) { - var softDeleteColumnName = modelBuilder.Entity().Metadata.FindProperty(nameof(ISoftDelete.IsDeleted))?.GetColumnName() ?? "IsDeleted"; + var softDeleteColumnName = entityTypeBuilder.Metadata.FindProperty(nameof(ISoftDelete.IsDeleted))?.GetColumnName() ?? "IsDeleted"; expression = e => !IsSoftDeleteFilterEnabled || !EF.Property(e, softDeleteColumnName); if (UseDbFunction()) { expression = e => AbpEfCoreDataFilterDbFunctionMethods.SoftDeleteFilter(((ISoftDelete)e).IsDeleted, true); - modelBuilder.ConfigureSoftDeleteDbFunction(AbpEfCoreDataFilterDbFunctionMethods.SoftDeleteFilterMethodInfo, this.GetService()); + modelBuilder.ConfigureSoftDeleteDbFunction( + AbpEfCoreDataFilterDbFunctionMethods.SoftDeleteFilterMethodInfo, + this.GetService() + ); } } if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity))) { - var multiTenantColumnName = modelBuilder.Entity().Metadata.FindProperty(nameof(IMultiTenant.TenantId))?.GetColumnName() ?? "TenantId"; + var multiTenantColumnName = entityTypeBuilder.Metadata.FindProperty(nameof(IMultiTenant.TenantId))?.GetColumnName() ?? "TenantId"; Expression> multiTenantFilter = e => !IsMultiTenantFilterEnabled || EF.Property(e, multiTenantColumnName) == CurrentTenantId; if (UseDbFunction()) { diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs index 833163d223..3097eba9cb 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs @@ -31,6 +31,9 @@ public interface IEfCoreDbContext : IDisposable, IInfrastructure Set() where T : class; + + DbSet Set(string name) + where T : class; DatabaseFacade Database { get; } diff --git a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs index 4a7a9fb28f..63aa0e3411 100644 --- a/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs +++ b/framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs @@ -408,6 +408,11 @@ public class RepositoryRegistration_Tests public class MyTestAggregateRootWithDefaultPkEmptyRepository : IMyTestAggregateRootWithDefaultPkEmptyRepository { public bool? IsChangeTrackingEnabled { get; set; } + + public void SetCustomEntityName(string name) + { + + } } public class TestDbContextRegistrationOptions : AbpCommonDbContextRegistrationOptions diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/SharedEntity_Repository_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/SharedEntity_Repository_Tests.cs new file mode 100644 index 0000000000..abdc7a4e6d --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/SharedEntity_Repository_Tests.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Data; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.MultiTenancy; +using Volo.Abp.TestApp.Domain; +using Xunit; + +namespace Volo.Abp.EntityFrameworkCore.Repositories; + +public class SharedEntity_Repository_Tests : EntityFrameworkCoreTestBase +{ + protected readonly IRepository TestSharedTypeEntityRepository; + protected readonly ICurrentTenant CurrentTenant; + protected readonly IDataFilter DataFilter; + + public SharedEntity_Repository_Tests() + { + TestSharedTypeEntityRepository = GetRequiredService>(); + CurrentTenant = GetRequiredService(); + DataFilter = GetRequiredService>(); + } + + [Fact] + public async Task SharedEntity_Test() + { + await WithUnitOfWorkAsync(async () => + { + TestSharedTypeEntityRepository.SetCustomEntityName("TestSharedEntity1"); + + var tenantId = Guid.NewGuid(); + await TestSharedTypeEntityRepository.InsertManyAsync(new List() + { + new TestSharedEntity(Guid.NewGuid()) + { + TenantId = null, + IsDeleted = false, + Name = "Test Person1", + Age = 10, + Birthday = DateTime.Now + }.SetProperty("testProperty", "Test Value1"), + new TestSharedEntity(Guid.NewGuid()) + { + TenantId = tenantId, + IsDeleted = false, + Name = "Test Person2", + Age = 20, + Birthday = DateTime.Now + }, + new TestSharedEntity(Guid.NewGuid()) + { + TenantId = tenantId, + IsDeleted = true, + Name = "Test Person3", + Age = 30, + Birthday = DateTime.Now + }, + new TestSharedEntity(Guid.NewGuid()) + { + TenantId = null, + IsDeleted = true, + Name = "Test Person4", + Age = 40, + Birthday = DateTime.Now + } + }, true); + + var entities = (await TestSharedTypeEntityRepository.GetListAsync()).OrderBy(x => x.Name).ToList(); + entities.Count.ShouldBe(1); + entities[0].TenantId.ShouldBeNull(); + entities[0].IsDeleted.ShouldBe(false); + entities[0].Name.ShouldBe("Test Person1"); + entities[0].Age.ShouldBe(10); + entities[0].GetProperty("testProperty").ShouldBe("Test Value1"); + + using (CurrentTenant.Change(tenantId)) + { + entities = (await TestSharedTypeEntityRepository.GetListAsync()).OrderBy(x => x.Name).ToList(); + entities.Count.ShouldBe(1); + entities[0].TenantId.ShouldBe(tenantId); + entities[0].IsDeleted.ShouldBe(false); + entities[0].Name.ShouldBe("Test Person2"); + entities[0].Age.ShouldBe(20); + } + + using (DataFilter.Disable()) + { + entities = (await TestSharedTypeEntityRepository.GetListAsync()).OrderBy(x => x.Name).ToList(); + entities.Count.ShouldBe(2); + + entities[0].TenantId.ShouldBeNull(); + entities[0].IsDeleted.ShouldBe(false); + entities[0].Name.ShouldBe("Test Person1"); + entities[0].Age.ShouldBe(10); + + entities[1].TenantId.ShouldBeNull(); + entities[1].IsDeleted.ShouldBe(true); + entities[1].Name.ShouldBe("Test Person4"); + entities[1].Age.ShouldBe(40); + } + + using (CurrentTenant.Change(tenantId)) + { + using (DataFilter.Disable()) + { + entities = (await TestSharedTypeEntityRepository.GetListAsync()).OrderBy(x => x.Name).ToList(); + entities.Count.ShouldBe(2); + + entities[0].TenantId.ShouldBe(tenantId); + entities[0].IsDeleted.ShouldBe(false); + entities[0].Name.ShouldBe("Test Person2"); + entities[0].Age.ShouldBe(20); + + entities[1].TenantId.ShouldBe(tenantId); + entities[1].IsDeleted.ShouldBe(true); + entities[1].Name.ShouldBe("Test Person3"); + entities[1].Age.ShouldBe(30); + } + } + + TestSharedTypeEntityRepository.SetCustomEntityName("TestSharedEntity2"); + await TestSharedTypeEntityRepository.InsertManyAsync(new List() + { + new TestSharedEntity(Guid.NewGuid()) + { + Name = "Test Person1 from Second Table", + Age = 110, + Birthday = DateTime.Now + } + }, true); + + var entitiesFromSecondTable = (await TestSharedTypeEntityRepository.GetListAsync()).OrderBy(x => x.Name).ToList(); + entitiesFromSecondTable.Count.ShouldBe(1); + entitiesFromSecondTable[0].TenantId.ShouldBeNull(); + entitiesFromSecondTable[0].IsDeleted.ShouldBe(false); + entitiesFromSecondTable[0].Name.ShouldBe("Test Person1 from Second Table"); + entitiesFromSecondTable[0].Age.ShouldBe(110); + }); + } + + [Fact] + public async Task SharedEntity_DynamicProperty_Test() + { + await WithUnitOfWorkAsync(async () => + { + TestSharedTypeEntityRepository.SetCustomEntityName("TestSharedEntity1"); + + var entity = new TestSharedEntity(Guid.NewGuid()) + { + TenantId = null, + IsDeleted = false, + Name = "Test Person1", + Age = 10, + Birthday = DateTime.Now + }; + + entity["DynamicProperty"] = "Test Value1"; + + await TestSharedTypeEntityRepository.InsertAsync(entity, true); + + entity = await TestSharedTypeEntityRepository.FindAsync(x => x.Id == entity.Id!); + entity.ShouldNotBeNull(); + + entity.Name.ShouldBe("Test Person1"); + entity.Age.ShouldBe(10); + entity.Birthday.ShouldNotBeNull(); + entity["DynamicProperty"].ShouldBe("Test Value1"); + + TestSharedTypeEntityRepository.SetCustomEntityName("TestSharedEntity2"); + entity = await TestSharedTypeEntityRepository.FindAsync(x => x.Id == entity.Id!); + entity.ShouldBeNull(); + }); + } +} 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 d05e367ff7..0efef5ba1f 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,6 @@ using System; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; using Volo.Abp.EntityFrameworkCore.Modeling; using Volo.Abp.EntityFrameworkCore.TestApp.SecondContext; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; @@ -33,6 +34,9 @@ public class TestMigrationsDbContext : AbpDbContext public DbSet Blogs { get; set; } public DbSet BlogPosts { get; set; } + public DbSet TestSharedEntity => Set("TestSharedEntity1"); + public DbSet TestSharedEntity2 => Set("TestSharedEntity2"); + public TestMigrationsDbContext(DbContextOptions options) : base(options) { @@ -41,8 +45,25 @@ public class TestMigrationsDbContext : AbpDbContext protected override void OnModelCreating(ModelBuilder modelBuilder) { + // Owned and SharedTypeEntity should be configured before the base OnModelCreating call + modelBuilder.Owned(); + Action> sharedEntityBuildAction = b => + { + b.ConfigureByConvention(); + b.Property(x => x.Id); + b.Property(x => x.TenantId); + b.Property(x => x.IsDeleted); + b.Property(x => x.Name); + b.Property(x => x.Age); + b.Property(x => x.Birthday); + + b.Property("DynamicProperty"); + }; + modelBuilder.SharedTypeEntity("TestSharedEntity1", sharedEntityBuildAction); + modelBuilder.SharedTypeEntity("TestSharedEntity2", sharedEntityBuildAction); + base.OnModelCreating(modelBuilder); modelBuilder.Entity(b => 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 242809bf7c..b2680abdff 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,7 +1,7 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.Extensions.Logging; +using Microsoft.EntityFrameworkCore.Metadata.Builders; using Volo.Abp.DependencyInjection; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.Modeling; @@ -40,6 +40,9 @@ public class TestAppDbContext : AbpDbContext, IThirdDbContext, public DbSet Blogs { get; set; } public DbSet BlogPosts { get; set; } + public DbSet TestSharedEntity => Set("TestSharedEntity1"); + public DbSet TestSharedEntity2 => Set("TestSharedEntity2"); + public TestAppDbContext(DbContextOptions options) : base(options) { @@ -54,8 +57,25 @@ public class TestAppDbContext : AbpDbContext, IThirdDbContext, protected override void OnModelCreating(ModelBuilder modelBuilder) { + // Owned and SharedTypeEntity should be configured before the base OnModelCreating call + modelBuilder.Owned(); + Action> sharedEntityBuildAction = b => + { + b.ConfigureByConvention(); + b.Property(x => x.Id); + b.Property(x => x.TenantId); + b.Property(x => x.IsDeleted); + b.Property(x => x.Name); + b.Property(x => x.Age); + b.Property(x => x.Birthday); + + b.Property("DynamicProperty"); + }; + modelBuilder.SharedTypeEntity("TestSharedEntity1", sharedEntityBuildAction); + modelBuilder.SharedTypeEntity("TestSharedEntity2", sharedEntityBuildAction); + base.OnModelCreating(modelBuilder); modelBuilder.Entity(b => diff --git a/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/TestSharedTypeEntity.cs b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/TestSharedTypeEntity.cs new file mode 100644 index 0000000000..5b1d94a316 --- /dev/null +++ b/framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/TestSharedTypeEntity.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Volo.Abp.Domain.Entities; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.TestApp.Domain; + +public class TestSharedEntity : AggregateRoot, IMultiTenant, ISoftDelete +{ + private readonly Dictionary _dynamicPropertites = new(); + + public object this[string key] + { + get => _dynamicPropertites.GetValueOrDefault(key); + set => _dynamicPropertites[key] = value; + } + + public Guid? TenantId { get; set; } + + public virtual string Name { get; set; } + + public virtual int Age { get; set; } + + public virtual DateTime? Birthday { get; set; } + + public bool IsDeleted { get; set; } + + public TestSharedEntity() + { + + } + + public TestSharedEntity(Guid id) + : base(id) + { + + } +}