diff --git a/docs/en/Entity-Framework-Core.md b/docs/en/Entity-Framework-Core.md index 241a08790f..fcbf5d8091 100644 --- a/docs/en/Entity-Framework-Core.md +++ b/docs/en/Entity-Framework-Core.md @@ -724,7 +724,19 @@ One advantage of using an interface for a DbContext is then it will be replaceab ### Replace Other DbContextes -Once you properly define and use an interface for DbContext, then any other implementation can replace it using the `ReplaceDbContext` option: +Once you properly define and use an interface for DbContext, then any other implementation can use the following ways to replace it: + +**ReplaceDbContextAttribute** + +```csharp +[ReplaceDbContext(typeof(IBookStoreDbContext))] +public class OtherDbContext : AbpDbContext, IBookStoreDbContext +{ + //... +} +``` + +**ReplaceDbContext option** ````csharp context.Services.AddAbpDbContext(options => diff --git a/docs/en/MongoDB.md b/docs/en/MongoDB.md index 5bcdfe7730..d99c40da43 100644 --- a/docs/en/MongoDB.md +++ b/docs/en/MongoDB.md @@ -391,7 +391,19 @@ One advantage of using interface for a MongoDbContext is then it becomes replace #### Replace Other DbContextes -Once you properly define and use an interface for a MongoDbContext , then any other implementation can replace it using the `ReplaceDbContext` option: +Once you properly define and use an interface for a MongoDbContext , then any other implementation can use the following ways to replace it: + +**ReplaceDbContextAttribute** + +```csharp +[ReplaceDbContext(typeof(IBookStoreMongoDbContext))] +public class OtherMongoDbContext : AbpMongoDbContext, IBookStoreMongoDbContext +{ + //... +} +``` + +**ReplaceDbContext option** ```csharp context.Services.AddMongoDbContext(options => diff --git a/docs/zh-Hans/Entity-Framework-Core.md b/docs/zh-Hans/Entity-Framework-Core.md index b5252b86c0..4139407f04 100644 --- a/docs/zh-Hans/Entity-Framework-Core.md +++ b/docs/zh-Hans/Entity-Framework-Core.md @@ -433,7 +433,19 @@ public class BookRepository : EfCoreRepository, ### 替换其他仓储 -正确定义并使用DbContext接口后,任何其他实现都可以使用以下ReplaceDbContext options 替换它: +正确定义并使用DbContext接口后,任何其他实现都可以使用以下方法替换它: + +**ReplaceDbContextAttribute** + +```csharp +[ReplaceDbContext(typeof(IBookStoreDbContext))] +public class OtherDbContext : AbpDbContext, IBookStoreDbContext +{ + //... +} +``` + +**ReplaceDbContext option** ````csharp context.Services.AddAbpDbContext(options => diff --git a/docs/zh-Hans/MongoDB.md b/docs/zh-Hans/MongoDB.md index af63642a41..87c99d3207 100644 --- a/docs/zh-Hans/MongoDB.md +++ b/docs/zh-Hans/MongoDB.md @@ -329,7 +329,19 @@ public class BookRepository ##### 替换其他的DbContexts -一旦你正确定义并为MongoDbContext使用了接口,其他的实现就可以使用`ReplaceDbContext`来替换: +一旦你正确定义并为MongoDbContext使用了接口,任何其他实现都可以使用以下方法替换它: + +**ReplaceDbContextAttribute** + +```csharp +[ReplaceDbContext(typeof(IBookStoreMongoDbContext))] +public class OtherMongoDbContext : AbpMongoDbContext, IBookStoreMongoDbContext +{ + //... +} +``` + +**ReplaceDbContext option** ```csharp context.Services.AddMongoDbContext(options => diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 160918667d..b71288ab93 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -395,6 +395,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Raz EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.TextTemplating.Scriban.Tests", "test\Volo.Abp.TextTemplating.Scriban.Tests\Volo.Abp.TextTemplating.Scriban.Tests.csproj", "{75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.MongoDB.Tests.SecondContext", "test\Volo.Abp.MongoDB.Tests.SecondContext\Volo.Abp.MongoDB.Tests.SecondContext.csproj", "{90B1866A-EF99-40B9-970E-B898E5AA523F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1177,6 +1179,10 @@ Global {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C}.Debug|Any CPU.Build.0 = Debug|Any CPU {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C}.Release|Any CPU.ActiveCfg = Release|Any CPU {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C}.Release|Any CPU.Build.0 = Release|Any CPU + {90B1866A-EF99-40B9-970E-B898E5AA523F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90B1866A-EF99-40B9-970E-B898E5AA523F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90B1866A-EF99-40B9-970E-B898E5AA523F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90B1866A-EF99-40B9-970E-B898E5AA523F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1376,6 +1382,7 @@ Global {42EA6F06-2D78-4D18-8AC4-8F2AB7E6DA19} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {C996F458-98FB-483D-9306-4701290E2FC1} = {447C8A77-E5F0-4538-8687-7383196D04EA} {75D8DADB-3FA9-4C1D-B23A-DBFD08133B7C} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {90B1866A-EF99-40B9-970E-B898E5AA523F} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/AbpCommonDbContextRegistrationOptions.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/AbpCommonDbContextRegistrationOptions.cs index 6408e3f0fa..ee172b3409 100644 --- a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/AbpCommonDbContextRegistrationOptions.cs +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/AbpCommonDbContextRegistrationOptions.cs @@ -55,7 +55,7 @@ namespace Volo.Abp.DependencyInjection throw new AbpException($"{OriginalDbContextType.AssemblyQualifiedName} should inherit/implement {otherDbContextType.AssemblyQualifiedName}!"); } - ReplacedDbContextTypes.Add(otherDbContextType); + ReplacedDbContextTypes.AddIfNotContains(otherDbContextType); return this; } @@ -93,9 +93,9 @@ namespace Volo.Abp.DependencyInjection public IAbpCommonDbContextRegistrationOptionsBuilder AddDefaultRepository(Type entityType) { EntityHelper.CheckEntity(entityType); - + SpecifiedDefaultRepositories.AddIfNotContains(entityType); - + return this; } diff --git a/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/ReplaceDbContextAttribute.cs b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/ReplaceDbContextAttribute.cs new file mode 100644 index 0000000000..625e6841a0 --- /dev/null +++ b/framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/DependencyInjection/ReplaceDbContextAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace Volo.Abp.DependencyInjection +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public class ReplaceDbContextAttribute : Attribute + { + public Type[] ReplacedDbContextTypes { get; } + + public ReplaceDbContextAttribute(params Type[] replacedDbContextTypes) + { + ReplacedDbContextTypes = replacedDbContextTypes; + } + } +} diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs index 538614ee22..a48575ddcc 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Microsoft/Extensions/DependencyInjection/AbpEfCoreServiceCollectionExtensions.cs @@ -1,5 +1,8 @@ using System; +using System.Linq; +using System.Reflection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp.DependencyInjection; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.DependencyInjection; @@ -8,13 +11,22 @@ namespace Microsoft.Extensions.DependencyInjection public static class AbpEfCoreServiceCollectionExtensions { public static IServiceCollection AddAbpDbContext( - this IServiceCollection services, + this IServiceCollection services, Action optionsBuilder = null) where TDbContext : AbpDbContext { services.AddMemoryCache(); var options = new AbpDbContextRegistrationOptions(typeof(TDbContext), services); + + var replacedDbContextTypes = typeof(TDbContext).GetCustomAttributes(true) + .SelectMany( x => x.ReplacedDbContextTypes).ToList(); + + foreach (var dbContextType in replacedDbContextTypes) + { + options.ReplaceDbContext(dbContextType); + } + optionsBuilder?.Invoke(options); services.TryAddTransient(DbContextOptionsFactory.Create); diff --git a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreModule.cs b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreModule.cs index e92c8d35fa..b5d9eb8436 100644 --- a/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreModule.cs +++ b/framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreModule.cs @@ -1,6 +1,8 @@ using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Domain; +using Volo.Abp.EntityFrameworkCore.DependencyInjection; using Volo.Abp.Modularity; using Volo.Abp.Uow.EntityFrameworkCore; diff --git a/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs b/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs index 5adf7300ee..7f9c6b8d42 100644 --- a/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs +++ b/framework/src/Volo.Abp.MongoDB/Microsoft/Extensions/DependencyInjection/AbpMongoDbServiceCollectionExtensions.cs @@ -1,5 +1,8 @@ using System; +using System.Linq; +using System.Reflection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp.DependencyInjection; using Volo.Abp.MongoDB; using Volo.Abp.MongoDB.DependencyInjection; @@ -11,13 +14,22 @@ namespace Microsoft.Extensions.DependencyInjection where TMongoDbContext : AbpMongoDbContext { var options = new AbpMongoDbContextRegistrationOptions(typeof(TMongoDbContext), services); + + var replacedDbContextTypes = typeof(TMongoDbContext).GetCustomAttributes(true) + .SelectMany( x => x.ReplacedDbContextTypes).ToList(); + + foreach (var dbContextType in replacedDbContextTypes) + { + options.ReplaceDbContext(dbContextType); + } + optionsBuilder?.Invoke(options); foreach (var dbContextType in options.ReplacedDbContextTypes) { services.Replace(ServiceDescriptor.Transient(dbContextType, typeof(TMongoDbContext))); } - + foreach (var dbContextType in options.ReplacedDbContextTypes) { services.Replace( diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DependencyInjection/AbpMongoDbConventionalRegistrar.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DependencyInjection/AbpMongoDbConventionalRegistrar.cs index cb1ed7ea54..e0a6265f7c 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DependencyInjection/AbpMongoDbConventionalRegistrar.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/DependencyInjection/AbpMongoDbConventionalRegistrar.cs @@ -1,5 +1,7 @@ using System; +using System.Reflection; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.DependencyInjection; namespace Volo.Abp.MongoDB.DependencyInjection diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/FourthContext/FourthDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/FourthContext/FourthDbContext.cs new file mode 100644 index 0000000000..5fa8a80367 --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/FourthContext/FourthDbContext.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; + +namespace Volo.Abp.EntityFrameworkCore.TestApp.FourthContext +{ + /* This dbcontext is just for testing to replace dbcontext from the application using ReplaceDbContextAttribute + */ + public class FourthDbContext : AbpDbContext, IFourthDbContext + { + public DbSet FourthDummyEntities { get; set; } + + public FourthDbContext(DbContextOptions options) + : base(options) + { + } + } +} diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/FourthContext/FourthDbContextDummyEntity.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/FourthContext/FourthDbContextDummyEntity.cs new file mode 100644 index 0000000000..8043301215 --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/FourthContext/FourthDbContextDummyEntity.cs @@ -0,0 +1,10 @@ +using System; +using Volo.Abp.Domain.Entities; + +namespace Volo.Abp.EntityFrameworkCore.TestApp.FourthContext +{ + public class FourthDbContextDummyEntity : AggregateRoot + { + public string Value { get; set; } + } +} diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/FourthContext/IFourthDbContext.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/FourthContext/IFourthDbContext.cs new file mode 100644 index 0000000000..eb2380d681 --- /dev/null +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/FourthContext/IFourthDbContext.cs @@ -0,0 +1,9 @@ +using Microsoft.EntityFrameworkCore; + +namespace Volo.Abp.EntityFrameworkCore.TestApp.FourthContext +{ + public interface IFourthDbContext : IEfCoreDbContext + { + DbSet FourthDummyEntities { get; set; } + } +} diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/AbpEfCoreTestSecondContextModule.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/AbpEfCoreTestSecondContextModule.cs index 80ece93c07..e5e02efa3b 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/AbpEfCoreTestSecondContextModule.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests.SecondContext/Volo/Abp/EntityFrameworkCore/TestApp/SecondContext/AbpEfCoreTestSecondContextModule.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.EntityFrameworkCore.TestApp.FourthContext; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; using Volo.Abp.Modularity; using Volo.Abp.Threading; @@ -19,6 +20,11 @@ namespace Volo.Abp.EntityFrameworkCore.TestApp.SecondContext { options.AddDefaultRepositories(); }); + + context.Services.AddAbpDbContext(options => + { + options.AddDefaultRepositories(); + }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) @@ -36,4 +42,4 @@ namespace Volo.Abp.EntityFrameworkCore.TestApp.SecondContext } } } -} \ No newline at end of file +} diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs index a1ca2e2846..4f8faef65e 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/AbpEntityFrameworkCoreTestModule.cs @@ -39,7 +39,7 @@ namespace Volo.Abp.EntityFrameworkCore { opt.DefaultWithDetailsFunc = q => q.Include(p => p.Phones); }); - + options.Entity(opt => { opt.DefaultWithDetailsFunc = q => q.Include(p => p.Books); @@ -76,7 +76,7 @@ namespace Volo.Abp.EntityFrameworkCore @"CREATE VIEW View_PersonView AS SELECT Name, CreationTime, Birthday, LastActive FROM People"); } - + return connection; } } diff --git a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs index 8fd88f23fe..4e343e7331 100644 --- a/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs +++ b/framework/test/Volo.Abp.EntityFrameworkCore.Tests/Volo/Abp/EntityFrameworkCore/DbContext_Replace_Tests.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Shouldly; using Volo.Abp.Domain.Repositories; +using Volo.Abp.EntityFrameworkCore.TestApp.FourthContext; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; using Volo.Abp.TestApp.Domain; using Volo.Abp.TestApp.EntityFrameworkCore; @@ -15,13 +16,15 @@ namespace Volo.Abp.EntityFrameworkCore public class DbContext_Replace_Tests : EntityFrameworkCoreTestBase { private readonly IBasicRepository _dummyRepository; - private readonly IPersonRepository _personRepository; + private readonly IBasicRepository _fourthDummyRepository; + private readonly IPersonRepository _personRepository; private readonly IUnitOfWorkManager _unitOfWorkManager; private readonly AbpDbContextOptions _options; public DbContext_Replace_Tests() { _dummyRepository = GetRequiredService>(); + _fourthDummyRepository = GetRequiredService>(); _personRepository = GetRequiredService(); _unitOfWorkManager = GetRequiredService(); _options = GetRequiredService>().Value; @@ -31,8 +34,10 @@ namespace Volo.Abp.EntityFrameworkCore public async Task Should_Replace_DbContext() { _options.GetReplacedTypeOrSelf(typeof(IThirdDbContext)).ShouldBe(typeof(TestAppDbContext)); - + _options.GetReplacedTypeOrSelf(typeof(IFourthDbContext)).ShouldBe(typeof(TestAppDbContext)); + (ServiceProvider.GetRequiredService() is TestAppDbContext).ShouldBeTrue(); + (ServiceProvider.GetRequiredService() is TestAppDbContext).ShouldBeTrue(); using (var uow = _unitOfWorkManager.Begin()) { @@ -44,11 +49,19 @@ namespace Volo.Abp.EntityFrameworkCore var instance3 = await _personRepository.GetDbContextAsync(); (instance3 is TestAppDbContext).ShouldBeTrue(); - + + var instance4 = await _fourthDummyRepository.GetDbContextAsync(); + (instance4 is IFourthDbContext).ShouldBeTrue(); + + var instance5 = await _fourthDummyRepository.GetDbContextAsync(); + (instance5 is TestAppDbContext).ShouldBeTrue(); + // All instances should be the same! instance3.ShouldBe(instance1); instance3.ShouldBe(instance2); - + instance3.ShouldBe(instance4); + instance3.ShouldBe(instance5); + await uow.CompleteAsync(); } } 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 da8bbc8a6c..cd8bb75b78 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,12 +1,17 @@ using Microsoft.EntityFrameworkCore; +using Volo.Abp.DependencyInjection; using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.TestApp.FourthContext; using Volo.Abp.EntityFrameworkCore.TestApp.ThirdDbContext; using Volo.Abp.TestApp.Domain; namespace Volo.Abp.TestApp.EntityFrameworkCore { - public class TestAppDbContext : AbpDbContext, IThirdDbContext + [ReplaceDbContext(typeof(IFourthDbContext))] + public class TestAppDbContext : AbpDbContext, IThirdDbContext, IFourthDbContext { + private DbSet _dummyEntities; + private DbSet _dummyEntities1; public DbSet People { get; set; } public DbSet Cities { get; set; } @@ -16,10 +21,12 @@ namespace Volo.Abp.TestApp.EntityFrameworkCore public DbSet DummyEntities { get; set; } public DbSet EntityWithIntPks { get; set; } - + public DbSet Author { get; set; } - public TestAppDbContext(DbContextOptions options) + public DbSet FourthDummyEntities { get; set; } + + public TestAppDbContext(DbContextOptions options) : base(options) { diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo.Abp.MongoDB.Tests.SecondContext.csproj b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo.Abp.MongoDB.Tests.SecondContext.csproj new file mode 100644 index 0000000000..e779329ad7 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo.Abp.MongoDB.Tests.SecondContext.csproj @@ -0,0 +1,19 @@ + + + + + + net5.0 + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + true + true + true + true + + + + + + + + diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/FourthContext/FourthDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/FourthContext/FourthDbContext.cs new file mode 100644 index 0000000000..7b496f954f --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/FourthContext/FourthDbContext.cs @@ -0,0 +1,13 @@ +using MongoDB.Driver; +using Volo.Abp.EntityFrameworkCore.TestApp.FourthContext; + +namespace Volo.Abp.MongoDB.TestApp.FourthContext +{ + /* This dbcontext is just for testing to replace dbcontext from the application using ReplaceDbContextAttribute + */ + public class FourthDbContext : AbpMongoDbContext, IFourthDbContext + { + public IMongoCollection FourthDummyEntities => Collection(); + + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/FourthContext/FourthDbContextDummyEntity.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/FourthContext/FourthDbContextDummyEntity.cs new file mode 100644 index 0000000000..8043301215 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/FourthContext/FourthDbContextDummyEntity.cs @@ -0,0 +1,10 @@ +using System; +using Volo.Abp.Domain.Entities; + +namespace Volo.Abp.EntityFrameworkCore.TestApp.FourthContext +{ + public class FourthDbContextDummyEntity : AggregateRoot + { + public string Value { get; set; } + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/FourthContext/IFourthDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/FourthContext/IFourthDbContext.cs new file mode 100644 index 0000000000..ae9ee2f281 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/FourthContext/IFourthDbContext.cs @@ -0,0 +1,10 @@ +using MongoDB.Driver; +using Volo.Abp.EntityFrameworkCore.TestApp.FourthContext; + +namespace Volo.Abp.MongoDB.TestApp.FourthContext +{ + public interface IFourthDbContext : IAbpMongoDbContext + { + IMongoCollection FourthDummyEntities { get;} + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/AbpMongoDbTestSecondContextModule.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/AbpMongoDbTestSecondContextModule.cs new file mode 100644 index 0000000000..ba5eaf7f79 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/AbpMongoDbTestSecondContextModule.cs @@ -0,0 +1,45 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; +using Volo.Abp.MongoDB.TestApp.FourthContext; +using Volo.Abp.MongoDB.TestApp.ThirdDbContext; +using Volo.Abp.Threading; + +namespace Volo.Abp.MongoDB.TestApp.SecondContext +{ + [DependsOn(typeof(AbpMongoDbModule))] + public class AbpMongoDbTestSecondContextModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddMongoDbContext(options => + { + options.AddDefaultRepositories(); + }); + + context.Services.AddMongoDbContext(options => + { + options.AddDefaultRepositories(); + }); + + context.Services.AddMongoDbContext(options => + { + options.AddDefaultRepositories(); + }); + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + SeedTestData(context); + } + + private static void SeedTestData(ApplicationInitializationContext context) + { + using (var scope = context.ServiceProvider.CreateScope()) + { + AsyncHelper.RunSync(() => scope.ServiceProvider + .GetRequiredService() + .BuildAsync()); + } + } + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/BookInSecondDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/BookInSecondDbContext.cs new file mode 100644 index 0000000000..d7e81f4258 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/BookInSecondDbContext.cs @@ -0,0 +1,21 @@ +using System; +using Volo.Abp.Domain.Entities; + +namespace Volo.Abp.MongoDB.TestApp.SecondContext +{ + public class BookInSecondDbContext : AggregateRoot + { + public string Name { get; set; } + + public BookInSecondDbContext() + { + + } + + public BookInSecondDbContext(Guid id, string name) + : base(id) + { + Name = name; + } + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/PhoneInSecondDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/PhoneInSecondDbContext.cs new file mode 100644 index 0000000000..d808d5a52a --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/PhoneInSecondDbContext.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations.Schema; +using Volo.Abp.Domain.Entities; + +namespace Volo.Abp.MongoDB.TestApp.SecondContext +{ + public class PhoneInSecondDbContext : AggregateRoot + { + public virtual Guid PersonId { get; set; } + + public virtual string Number { get; set; } + + public override object[] GetKeys() + { + return new object[] {PersonId, Number}; + } + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/SecondContextTestDataBuilder.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/SecondContextTestDataBuilder.cs new file mode 100644 index 0000000000..c3fb902c64 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/SecondContextTestDataBuilder.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Guids; + +namespace Volo.Abp.MongoDB.TestApp.SecondContext +{ + public class SecondContextTestDataBuilder : ITransientDependency + { + private readonly IBasicRepository _bookRepository; + private readonly IGuidGenerator _guidGenerator; + + public SecondContextTestDataBuilder(IBasicRepository bookRepository, IGuidGenerator guidGenerator) + { + _bookRepository = bookRepository; + _guidGenerator = guidGenerator; + } + + public async Task BuildAsync() + { + await _bookRepository.InsertAsync( + new BookInSecondDbContext( + _guidGenerator.Create(), + "TestBook1" + ) + ); + } + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/SecondDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/SecondDbContext.cs new file mode 100644 index 0000000000..2df5785b20 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/SecondContext/SecondDbContext.cs @@ -0,0 +1,11 @@ +using MongoDB.Driver; + +namespace Volo.Abp.MongoDB.TestApp.SecondContext +{ + public class SecondDbContext : AbpMongoDbContext + { + public IMongoCollection Books => Collection(); + + public IMongoCollection Phones => Collection(); + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/ThirdDbContext/IThirdDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/ThirdDbContext/IThirdDbContext.cs new file mode 100644 index 0000000000..cfe629b5a7 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/ThirdDbContext/IThirdDbContext.cs @@ -0,0 +1,9 @@ +using MongoDB.Driver; + +namespace Volo.Abp.MongoDB.TestApp.ThirdDbContext +{ + public interface IThirdDbContext : IAbpMongoDbContext + { + IMongoCollection DummyEntities { get; } + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/ThirdDbContext/ThirdDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/ThirdDbContext/ThirdDbContext.cs new file mode 100644 index 0000000000..c3b018a699 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/ThirdDbContext/ThirdDbContext.cs @@ -0,0 +1,11 @@ +using MongoDB.Driver; + +namespace Volo.Abp.MongoDB.TestApp.ThirdDbContext +{ + /* This dbcontext is just for testing to replace dbcontext from the application using AbpDbContextRegistrationOptions.ReplaceDbContext + */ + public class ThirdDbContext : AbpMongoDbContext, IThirdDbContext + { + public IMongoCollection DummyEntities => Collection(); + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/ThirdDbContext/ThirdDbContextDummyEntity.cs b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/ThirdDbContext/ThirdDbContextDummyEntity.cs new file mode 100644 index 0000000000..a784406ff5 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests.SecondContext/Volo/Abp/MongoDB/TestApp/ThirdDbContext/ThirdDbContextDummyEntity.cs @@ -0,0 +1,10 @@ +using System; +using Volo.Abp.Domain.Entities; + +namespace Volo.Abp.MongoDB.TestApp.ThirdDbContext +{ + public class ThirdDbContextDummyEntity : AggregateRoot + { + public string Value { get; set; } + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj b/framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj index c36fbb799c..21bcac616e 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo.Abp.MongoDB.Tests.csproj @@ -9,8 +9,8 @@ - + diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/AbpMongoDbTestModule.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/AbpMongoDbTestModule.cs index e580c6fce6..100011560e 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/AbpMongoDbTestModule.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/AbpMongoDbTestModule.cs @@ -1,21 +1,18 @@ using System; -using System.Linq; -using System.Threading; using Microsoft.Extensions.DependencyInjection; -using MongoDB.Driver; -using MongoDB.Driver.Core.Servers; using Volo.Abp.Data; using Volo.Abp.Modularity; +using Volo.Abp.MongoDB.TestApp.SecondContext; +using Volo.Abp.MongoDB.TestApp.ThirdDbContext; using Volo.Abp.TestApp; using Volo.Abp.TestApp.Domain; using Volo.Abp.TestApp.MongoDB; -using Volo.Abp.Uow; namespace Volo.Abp.MongoDB { [DependsOn( - typeof(AbpMongoDbModule), - typeof(TestAppModule) + typeof(TestAppModule), + typeof(AbpMongoDbTestSecondContextModule) )] public class AbpMongoDbTestModule : AbpModule { @@ -35,6 +32,8 @@ namespace Volo.Abp.MongoDB { options.AddDefaultRepositories(); options.AddRepository(); + + options.ReplaceDbContext(); }); } } diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/DbContext_Replace_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/DbContext_Replace_Tests.cs new file mode 100644 index 0000000000..eefa6852bf --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/DbContext_Replace_Tests.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Shouldly; +using Volo.Abp.MongoDB.TestApp.FourthContext; +using Volo.Abp.MongoDB.TestApp.ThirdDbContext; +using Volo.Abp.TestApp.MongoDB; +using Xunit; + +namespace Volo.Abp.MongoDB +{ + [Collection(MongoTestCollection.Name)] + public class DbContext_Replace_Tests : MongoDbTestBase + { + private readonly AbpMongoDbContextOptions _options; + + public DbContext_Replace_Tests() + { + _options = GetRequiredService>().Value; + } + + [Fact] + public void Should_Replace_DbContext() + { + _options.GetReplacedTypeOrSelf(typeof(IThirdDbContext)).ShouldBe(typeof(TestAppMongoDbContext)); + _options.GetReplacedTypeOrSelf(typeof(IFourthDbContext)).ShouldBe(typeof(TestAppMongoDbContext)); + + (ServiceProvider.GetRequiredService() is TestAppMongoDbContext).ShouldBeTrue(); + (ServiceProvider.GetRequiredService() is TestAppMongoDbContext).ShouldBeTrue(); + } + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs index eed8d4ade3..68a2856e01 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/TestApp/MongoDb/TestAppMongoDbContext.cs @@ -1,12 +1,17 @@ using MongoDB.Driver; using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EntityFrameworkCore.TestApp.FourthContext; using Volo.Abp.MongoDB; +using Volo.Abp.MongoDB.TestApp.FourthContext; +using Volo.Abp.MongoDB.TestApp.ThirdDbContext; using Volo.Abp.TestApp.Domain; namespace Volo.Abp.TestApp.MongoDB { [ConnectionStringName("TestApp")] - public class TestAppMongoDbContext : AbpMongoDbContext, ITestAppMongoDbContext + [ReplaceDbContext(typeof(IFourthDbContext))] + public class TestAppMongoDbContext : AbpMongoDbContext, ITestAppMongoDbContext, IThirdDbContext, IFourthDbContext { [MongoCollection("Persons")] //Intentionally changed the collection name to test it public IMongoCollection People => Collection(); @@ -15,6 +20,10 @@ namespace Volo.Abp.TestApp.MongoDB public IMongoCollection Cities => Collection(); + public IMongoCollection DummyEntities => Collection(); + + public IMongoCollection FourthDummyEntities => Collection(); + protected internal override void CreateModel(IMongoModelBuilder modelBuilder) { base.CreateModel(modelBuilder);