Browse Source

Merge pull request #23588 from abpframework/ef-core-shared-entity-types

Support EF Core Shared Entity Types on Repositories
pull/23596/head
Ma Liming 1 year ago
committed by GitHub
parent
commit
f4b6b51865
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 7
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs
  2. 2
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/IRepository.cs
  3. 31
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs
  4. 94
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpDbContext.cs
  5. 3
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs
  6. 5
      framework/test/Volo.Abp.Ddd.Tests/Volo/Abp/Domain/Repositories/RepositoryRegistration_Tests.cs
  7. 177
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/Repositories/SharedEntity_Repository_Tests.cs
  8. 21
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/TestMigrationsDbContext.cs
  9. 22
      framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/TestApp/EntityFrameworkCore/TestAppDbContext.cs
  10. 38
      framework/test/Volo.Abp.TestApp/Volo/Abp/TestApp/Domain/TestSharedTypeEntity.cs

7
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Domain/Repositories/BasicRepositoryBase.cs

@ -43,6 +43,13 @@ public abstract class BasicRepositoryBase<TEntity> :
public IEntityChangeTrackingProvider EntityChangeTrackingProvider => LazyServiceProvider.LazyGetRequiredService<IEntityChangeTrackingProvider>();
public bool? IsChangeTrackingEnabled { get; protected set; }
protected string? CustomEntityName { get; private set; }
public void SetCustomEntityName(string? name)
{
CustomEntityName = name;
}
protected BasicRepositoryBase()
{

2
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<TEntity> : IReadOnlyRepository<TEntity>, IBasicRepository<TEntity>

31
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/Domain/Repositories/EntityFrameworkCore/EfCoreRepository.cs

@ -61,7 +61,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
}
[Obsolete("Use GetDbSetAsync() method.")]
public virtual DbSet<TEntity> DbSet => DbContext.Set<TEntity>();
public virtual DbSet<TEntity> DbSet => GetDbSetInternal(DbContext);
Task<DbSet<TEntity>> IEfCoreRepository<TEntity>.GetDbSetAsync()
{
@ -70,7 +70,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
protected async Task<DbSet<TEntity>> GetDbSetAsync()
{
return (await GetDbContextAsync()).Set<TEntity>();
return GetDbSetInternal(await GetDbContextAsync());
}
protected async Task<IDbConnection> GetDbConnectionAsync()
@ -110,7 +110,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
var dbContext = await GetDbContextAsync();
var savedEntity = (await dbContext.Set<TEntity>().AddAsync(entity, GetCancellationToken(cancellationToken))).Entity;
var savedEntity = (await GetDbSetInternal(dbContext).AddAsync(entity, GetCancellationToken(cancellationToken))).Entity;
if (autoSave)
{
@ -120,6 +120,13 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
return savedEntity;
}
private DbSet<TEntity> GetDbSetInternal(TDbContext dbContext)
{
return CustomEntityName != null
? dbContext.Set<TEntity>(CustomEntityName)
: dbContext.Set<TEntity>();
}
public async override Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
var entityArray = entities.ToArray();
@ -147,7 +154,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
return;
}
await dbContext.Set<TEntity>().AddRangeAsync(entityArray, cancellationToken);
await GetDbSetInternal(dbContext).AddRangeAsync(entityArray, cancellationToken);
if (autoSave)
{
@ -159,9 +166,10 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
{
var dbContext = await GetDbContextAsync();
if (dbContext.Set<TEntity>().Local.All(e => e != entity))
var dbSet = GetDbSetInternal(dbContext);
if (dbSet.Local.All(e => e != entity))
{
dbContext.Set<TEntity>().Attach(entity);
dbSet.Attach(entity);
dbContext.Update(entity);
}
@ -197,7 +205,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
var dbContext = await GetDbContextAsync();
dbContext.Set<TEntity>().UpdateRange(entityArray);
GetDbSetInternal(dbContext).UpdateRange(entityArray);
if (autoSave)
{
@ -209,7 +217,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
{
var dbContext = await GetDbContextAsync();
dbContext.Set<TEntity>().Remove(entity);
GetDbSetInternal(dbContext).Remove(entity);
if (autoSave)
{
@ -318,7 +326,7 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
public async override Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
{
var dbContext = await GetDbContextAsync();
var dbSet = dbContext.Set<TEntity>();
var dbSet = GetDbSetInternal(dbContext);
var entities = await dbSet
.Where(predicate)
@ -335,8 +343,9 @@ public class EfCoreRepository<TDbContext, TEntity> : RepositoryBase<TEntity>, IE
public async override Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default)
{
var dbContext = await GetDbContextAsync();
var dbSet = dbContext.Set<TEntity>();
await dbSet.Where(predicate).ExecuteDeleteAsync(GetCancellationToken(cancellationToken));
await GetDbSetInternal(dbContext)
.Where(predicate)
.ExecuteDeleteAsync(GetCancellationToken(cancellationToken));
}
public virtual async Task EnsureCollectionLoadedAsync<TProperty>(

94
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<TDbContext> : 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<TDbContext> : 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<TDbContext> : DbContext, IAbpEfCoreDbContext,
AuditPropertySetter?.IncrementEntityVersionProperty(entry.Entity);
}
protected virtual void ConfigureBaseProperties<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
protected virtual void ConfigureBaseProperties<TEntity>(
ModelBuilder modelBuilder,
IMutableEntityType mutableEntityType)
where TEntity : class
{
if (mutableEntityType.IsOwned())
@ -775,25 +785,44 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
return;
}
modelBuilder.Entity<TEntity>().ConfigureByConvention();
var entityTypeBuilder = CreateEntityTypeBuilderFromMutableEntityType<TEntity>(
modelBuilder,
mutableEntityType
);
entityTypeBuilder.ConfigureByConvention();
ConfigureGlobalFilters<TEntity>(modelBuilder, mutableEntityType, entityTypeBuilder);
}
ConfigureGlobalFilters<TEntity>(modelBuilder, mutableEntityType);
protected virtual EntityTypeBuilder<TEntity> CreateEntityTypeBuilderFromMutableEntityType<TEntity>(
ModelBuilder modelBuilder,
IMutableEntityType mutableEntityType) where TEntity : class
{
return mutableEntityType.HasSharedClrType
? modelBuilder.SharedTypeEntity<TEntity>(mutableEntityType.Name)
: modelBuilder.Entity<TEntity>();
}
protected virtual void ConfigureGlobalFilters<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
protected virtual void ConfigureGlobalFilters<TEntity>(
ModelBuilder modelBuilder,
IMutableEntityType mutableEntityType,
EntityTypeBuilder<TEntity> entityTypeBuilder)
where TEntity : class
{
if (mutableEntityType.BaseType == null && ShouldFilterEntity<TEntity>(mutableEntityType))
{
var filterExpression = CreateFilterExpression<TEntity>(modelBuilder);
var filterExpression = CreateFilterExpression<TEntity>(modelBuilder, entityTypeBuilder);
if (filterExpression != null)
{
modelBuilder.Entity<TEntity>().HasAbpQueryFilter(filterExpression);
entityTypeBuilder.HasAbpQueryFilter(filterExpression);
}
}
}
protected virtual void ConfigureValueConverter<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
protected virtual void ConfigureValueConverter<TEntity>(
ModelBuilder modelBuilder,
IMutableEntityType mutableEntityType)
where TEntity : class
{
if (mutableEntityType.BaseType != null ||
@ -808,6 +837,7 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
{
return;
}
foreach (var property in mutableEntityType.GetProperties().
Where(property => property.PropertyInfo != null &&
@ -815,8 +845,12 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
property.PropertyInfo.CanWrite &&
ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableDateTimeNormalizationAttribute>(property.PropertyInfo) == null))
{
modelBuilder
.Entity<TEntity>()
var entityTypeBuilder = CreateEntityTypeBuilderFromMutableEntityType<TEntity>(
modelBuilder,
mutableEntityType
);
entityTypeBuilder
.Property(property.Name)
.HasConversion(property.ClrType == typeof(DateTime)
? new AbpDateTimeValueConverter(Clock)
@ -824,7 +858,9 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
}
}
protected virtual void ConfigureValueGenerated<TEntity>(ModelBuilder modelBuilder, IMutableEntityType mutableEntityType)
protected virtual void ConfigureValueGenerated<TEntity>(
ModelBuilder modelBuilder,
IMutableEntityType mutableEntityType)
where TEntity : class
{
if (!typeof(IEntity<Guid>).IsAssignableFrom(typeof(TEntity)))
@ -832,7 +868,8 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
return;
}
var idPropertyBuilder = modelBuilder.Entity<TEntity>().Property(x => ((IEntity<Guid>)x).Id);
var entityTypeBuilder = CreateEntityTypeBuilderFromMutableEntityType<TEntity>(modelBuilder, mutableEntityType);
var idPropertyBuilder = entityTypeBuilder.Property(x => ((IEntity<Guid>)x).Id);
if (idPropertyBuilder.Metadata.PropertyInfo!.IsDefined(typeof(DatabaseGeneratedAttribute), true))
{
return;
@ -856,25 +893,30 @@ public abstract class AbpDbContext<TDbContext> : DbContext, IAbpEfCoreDbContext,
return false;
}
protected virtual Expression<Func<TEntity, bool>>? CreateFilterExpression<TEntity>(ModelBuilder modelBuilder)
protected virtual Expression<Func<TEntity, bool>>? CreateFilterExpression<TEntity>(
ModelBuilder modelBuilder,
EntityTypeBuilder<TEntity> entityTypeBuilder)
where TEntity : class
{
Expression<Func<TEntity, bool>>? expression = null;
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
var softDeleteColumnName = modelBuilder.Entity<TEntity>().Metadata.FindProperty(nameof(ISoftDelete.IsDeleted))?.GetColumnName() ?? "IsDeleted";
var softDeleteColumnName = entityTypeBuilder.Metadata.FindProperty(nameof(ISoftDelete.IsDeleted))?.GetColumnName() ?? "IsDeleted";
expression = e => !IsSoftDeleteFilterEnabled || !EF.Property<bool>(e, softDeleteColumnName);
if (UseDbFunction())
{
expression = e => AbpEfCoreDataFilterDbFunctionMethods.SoftDeleteFilter(((ISoftDelete)e).IsDeleted, true);
modelBuilder.ConfigureSoftDeleteDbFunction(AbpEfCoreDataFilterDbFunctionMethods.SoftDeleteFilterMethodInfo, this.GetService<AbpEfCoreCurrentDbContext>());
modelBuilder.ConfigureSoftDeleteDbFunction(
AbpEfCoreDataFilterDbFunctionMethods.SoftDeleteFilterMethodInfo,
this.GetService<AbpEfCoreCurrentDbContext>()
);
}
}
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{
var multiTenantColumnName = modelBuilder.Entity<TEntity>().Metadata.FindProperty(nameof(IMultiTenant.TenantId))?.GetColumnName() ?? "TenantId";
var multiTenantColumnName = entityTypeBuilder.Metadata.FindProperty(nameof(IMultiTenant.TenantId))?.GetColumnName() ?? "TenantId";
Expression<Func<TEntity, bool>> multiTenantFilter = e => !IsMultiTenantFilterEnabled || EF.Property<Guid>(e, multiTenantColumnName) == CurrentTenantId;
if (UseDbFunction())
{

3
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/IEfCoreDbContext.cs

@ -31,6 +31,9 @@ public interface IEfCoreDbContext : IDisposable, IInfrastructure<IServiceProvide
DbSet<T> Set<T>()
where T : class;
DbSet<T> Set<T>(string name)
where T : class;
DatabaseFacade Database { get; }

5
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

177
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<TestSharedEntity> TestSharedTypeEntityRepository;
protected readonly ICurrentTenant CurrentTenant;
protected readonly IDataFilter<ISoftDelete> DataFilter;
public SharedEntity_Repository_Tests()
{
TestSharedTypeEntityRepository = GetRequiredService<IRepository<TestSharedEntity>>();
CurrentTenant = GetRequiredService<ICurrentTenant>();
DataFilter = GetRequiredService<IDataFilter<ISoftDelete>>();
}
[Fact]
public async Task SharedEntity_Test()
{
await WithUnitOfWorkAsync(async () =>
{
TestSharedTypeEntityRepository.SetCustomEntityName("TestSharedEntity1");
var tenantId = Guid.NewGuid();
await TestSharedTypeEntityRepository.InsertManyAsync(new List<TestSharedEntity>()
{
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<TestSharedEntity>()
{
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();
});
}
}

21
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<TestMigrationsDbContext>
public DbSet<Blog> Blogs { get; set; }
public DbSet<BlogPost> BlogPosts { get; set; }
public DbSet<TestSharedEntity> TestSharedEntity => Set<TestSharedEntity>("TestSharedEntity1");
public DbSet<TestSharedEntity> TestSharedEntity2 => Set<TestSharedEntity>("TestSharedEntity2");
public TestMigrationsDbContext(DbContextOptions<TestMigrationsDbContext> options)
: base(options)
{
@ -41,8 +45,25 @@ public class TestMigrationsDbContext : AbpDbContext<TestMigrationsDbContext>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Owned and SharedTypeEntity should be configured before the base OnModelCreating call
modelBuilder.Owned<District>();
Action<EntityTypeBuilder<TestSharedEntity>> 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<string>("DynamicProperty");
};
modelBuilder.SharedTypeEntity("TestSharedEntity1", sharedEntityBuildAction);
modelBuilder.SharedTypeEntity("TestSharedEntity2", sharedEntityBuildAction);
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Phone>(b =>

22
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<TestAppDbContext>, IThirdDbContext,
public DbSet<Blog> Blogs { get; set; }
public DbSet<BlogPost> BlogPosts { get; set; }
public DbSet<TestSharedEntity> TestSharedEntity => Set<TestSharedEntity>("TestSharedEntity1");
public DbSet<TestSharedEntity> TestSharedEntity2 => Set<TestSharedEntity>("TestSharedEntity2");
public TestAppDbContext(DbContextOptions<TestAppDbContext> options)
: base(options)
{
@ -54,8 +57,25 @@ public class TestAppDbContext : AbpDbContext<TestAppDbContext>, IThirdDbContext,
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Owned and SharedTypeEntity should be configured before the base OnModelCreating call
modelBuilder.Owned<District>();
Action<EntityTypeBuilder<TestSharedEntity>> 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<string>("DynamicProperty");
};
modelBuilder.SharedTypeEntity("TestSharedEntity1", sharedEntityBuildAction);
modelBuilder.SharedTypeEntity("TestSharedEntity2", sharedEntityBuildAction);
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Phone>(b =>

38
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<Guid>, IMultiTenant, ISoftDelete
{
private readonly Dictionary<string, object> _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)
{
}
}
Loading…
Cancel
Save