diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs index 0f930d1f70..45729fcb86 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System; +using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; @@ -25,13 +27,31 @@ public class DataSeeder : IDataSeeder, ITransientDependency { using (var scope = ServiceScopeFactory.CreateScope()) { - foreach (var contributorType in Options.Contributors) + if (context.Properties.ContainsKey(DataSeederExtensions.SeedInSeparateUow)) { - var contributor = (IDataSeedContributor)scope - .ServiceProvider - .GetRequiredService(contributorType); + var manager = scope.ServiceProvider.GetRequiredService(); + foreach (var contributorType in Options.Contributors) + { + var options = context.Properties.TryGetValue(DataSeederExtensions.SeedInSeparateUowOptions, out var uowOptions) + ? (AbpUnitOfWorkOptions) uowOptions + : new AbpUnitOfWorkOptions(); + var requiresNew = context.Properties.TryGetValue(DataSeederExtensions.SeedInSeparateUowRequiresNew, out var obj) && (bool) obj; - await contributor.SeedAsync(context); + using (var uow = manager.Begin(options, requiresNew)) + { + var contributor = (IDataSeedContributor)scope.ServiceProvider.GetRequiredService(contributorType); + await contributor.SeedAsync(context); + await uow.CompleteAsync(); + } + } + } + else + { + foreach (var contributorType in Options.Contributors) + { + var contributor = (IDataSeedContributor)scope.ServiceProvider.GetRequiredService(contributorType); + await contributor.SeedAsync(context); + } } } } diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeederExtensions.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeederExtensions.cs index 83fa974d85..bd17736b46 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeederExtensions.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeederExtensions.cs @@ -1,12 +1,26 @@ using System; using System.Threading.Tasks; +using Volo.Abp.Uow; namespace Volo.Abp.Data; public static class DataSeederExtensions { + public const string SeedInSeparateUow = "__SeedInSeparateUow"; + public const string SeedInSeparateUowOptions = "__SeedInSeparateUowOptions"; + public const string SeedInSeparateUowRequiresNew = "__SeedInSeparateUowRequiresNew"; + public static Task SeedAsync(this IDataSeeder seeder, Guid? tenantId = null) { return seeder.SeedAsync(new DataSeedContext(tenantId)); } + + public static Task SeedInSeparateUowAsync(this IDataSeeder seeder, Guid? tenantId = null, AbpUnitOfWorkOptions options = null, bool requiresNew = false) + { + var context = new DataSeedContext(tenantId); + context.WithProperty(SeedInSeparateUow, true); + context.WithProperty(SeedInSeparateUowOptions, options); + context.WithProperty(SeedInSeparateUowRequiresNew, requiresNew); + return seeder.SeedAsync(context); + } } diff --git a/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/DataSeederExtensions_Tests.cs b/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/DataSeederExtensions_Tests.cs new file mode 100644 index 0000000000..25d20b58b5 --- /dev/null +++ b/framework/test/Volo.Abp.Data.Tests/Volo/Abp/Data/DataSeederExtensions_Tests.cs @@ -0,0 +1,43 @@ +using System; +using System.Data; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using NSubstitute; +using Volo.Abp.Modularity; +using Volo.Abp.Testing; +using Volo.Abp.Uow; +using Xunit; + +namespace Volo.Abp.Data; + +public class DataSeederExtensions_Tests : AbpIntegratedTest +{ + private IDataSeeder _dataSeeder; + + protected override void AfterAddApplication(IServiceCollection services) + { + _dataSeeder = Substitute.For(); + services.Replace(ServiceDescriptor.Singleton(_dataSeeder)); + base.AfterAddApplication(services); + } + + [Fact] + public void SeedInSeparateUowAsync() + { + var tenantId = Guid.NewGuid(); + _dataSeeder.SeedInSeparateUowAsync(tenantId, new AbpUnitOfWorkOptions(true, IsolationLevel.Serializable, 888), true); + + _dataSeeder.Received().SeedAsync(Arg.Is(x => x.TenantId == tenantId && + x.Properties[DataSeederExtensions.SeedInSeparateUow].To() == true && + x.Properties[DataSeederExtensions.SeedInSeparateUowOptions].As().IsTransactional == true && + x.Properties[DataSeederExtensions.SeedInSeparateUowOptions].As().IsolationLevel == IsolationLevel.Serializable && + x.Properties[DataSeederExtensions.SeedInSeparateUowOptions].As().Timeout == 888 && + x.Properties[DataSeederExtensions.SeedInSeparateUowRequiresNew].To() == true)); + } + + [DependsOn(typeof(AbpDataModule))] + public class TestModule : AbpModule + { + + } +}