From 0c3e45f0eadb5193ba0335131560e0fbd08accd7 Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Wed, 27 Mar 2019 14:51:26 +0300 Subject: [PATCH] Resolved #924: Create a data seed system --- .../Volo/Abp/Data/AbpDataModule.cs | 27 ++++++++++- .../Volo.Abp.Data/Volo/Abp/Data/DataFilter.cs | 1 + .../Volo/Abp/Data/DataSeedContext.cs | 48 +++++++++++++++++++ .../Volo/Abp/Data/DataSeedContributorList.cs | 9 ++++ .../Volo/Abp/Data/DataSeedOptions.cs | 12 +++++ .../Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs | 37 ++++++++++++++ .../Volo/Abp/Data/DataSeederExtensions.cs | 13 +++++ .../Volo/Abp/Data/IDataSeeder.cs | 9 ++++ 8 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContext.cs create mode 100644 framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContributorList.cs create mode 100644 framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedOptions.cs create mode 100644 framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs create mode 100644 framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeederExtensions.cs create mode 100644 framework/src/Volo.Abp.Data/Volo/Abp/Data/IDataSeeder.cs diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs index c7fa93a664..428d9d6313 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/AbpDataModule.cs @@ -1,10 +1,17 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Modularity; namespace Volo.Abp.Data { public class AbpDataModule : AbpModule { + public override void PreConfigureServices(ServiceConfigurationContext context) + { + AutoAddDataSeedContributors(context.Services); + } + public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); @@ -13,5 +20,23 @@ namespace Volo.Abp.Data context.Services.AddSingleton(typeof(IDataFilter<>), typeof(DataFilter<>)); } + + private static void AutoAddDataSeedContributors(IServiceCollection services) + { + var contributors = new List(); + + services.OnRegistred(context => + { + if (typeof(IDataSeedContributor).IsAssignableFrom(context.ImplementationType)) + { + contributors.Add(context.ImplementationType); + } + }); + + services.Configure(options => + { + options.Contributors.AddIfNotContains(contributors); + }); + } } } diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataFilter.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataFilter.cs index d4627d2683..73741dcfcb 100644 --- a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataFilter.cs +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataFilter.cs @@ -8,6 +8,7 @@ using Volo.Abp.DependencyInjection; namespace Volo.Abp.Data { + //TODO: Create a Volo.Abp.Data.Filtering namespace? public class DataFilter : IDataFilter, ISingletonDependency { private readonly ConcurrentDictionary _filters; diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContext.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContext.cs new file mode 100644 index 0000000000..6cda2f6e39 --- /dev/null +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContext.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace Volo.Abp.Data +{ + public class DataSeedContext + { + public Guid? TenantId { get; set; } + + /// + /// Gets/sets a key-value on the . + /// + /// Name of the property + /// + /// Returns the value in the dictionary by given . + /// Returns null if given is not present in the dictionary. + /// + [CanBeNull] + public object this[string name] + { + get => Properties.GetOrDefault(name); + set => Properties[name] = value; + } + + /// + /// Can be used to get/set custom properties. + /// + [NotNull] + public Dictionary Properties { get; } + + public DataSeedContext(Guid? tenantId = null) + { + TenantId = tenantId; + Properties = new Dictionary(); + } + + /// + /// Sets a property in the dictionary. + /// This is a shortcut for nested calls on this object. + /// + public virtual DataSeedContext WithProperty(string key, object value) + { + Properties[key] = value; + return this; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContributorList.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContributorList.cs new file mode 100644 index 0000000000..2d16c3c093 --- /dev/null +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedContributorList.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Collections; + +namespace Volo.Abp.Data +{ + public class DataSeedContributorList : TypeList + { + + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedOptions.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedOptions.cs new file mode 100644 index 0000000000..940f68175d --- /dev/null +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeedOptions.cs @@ -0,0 +1,12 @@ +namespace Volo.Abp.Data +{ + public class DataSeedOptions + { + public DataSeedContributorList Contributors { get; } + + public DataSeedOptions() + { + Contributors = new DataSeedContributorList(); + } + } +} diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs new file mode 100644 index 0000000000..e55f6c633b --- /dev/null +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeeder.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Data +{ + //TODO: Create a Volo.Abp.Data.Seeding namespace? + public class DataSeeder : IDataSeeder, ITransientDependency + { + protected IHybridServiceScopeFactory ServiceScopeFactory { get; } + protected DataSeedOptions Options { get; } + + public DataSeeder( + IOptions options, + IHybridServiceScopeFactory serviceScopeFactory) + { + ServiceScopeFactory = serviceScopeFactory; + Options = options.Value; + } + + public async Task SeedAsync(DataSeedContext context) + { + using (var scope = ServiceScopeFactory.CreateScope()) + { + foreach (var contributorType in Options.Contributors) + { + var contributor = (IDataSeedContributor) scope + .ServiceProvider + .GetRequiredService(contributorType); + + await contributor.SeedAsync(context); + } + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeederExtensions.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeederExtensions.cs new file mode 100644 index 0000000000..8208d02d2c --- /dev/null +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/DataSeederExtensions.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; + +namespace Volo.Abp.Data +{ + public static class DataSeederExtensions + { + public static Task SeedAsync(this IDataSeeder seeder, Guid? tenantId = null) + { + return seeder.SeedAsync(new DataSeedContext(tenantId)); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Data/Volo/Abp/Data/IDataSeeder.cs b/framework/src/Volo.Abp.Data/Volo/Abp/Data/IDataSeeder.cs new file mode 100644 index 0000000000..95ad1b7e8d --- /dev/null +++ b/framework/src/Volo.Abp.Data/Volo/Abp/Data/IDataSeeder.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.Data +{ + public interface IDataSeeder + { + Task SeedAsync(DataSeedContext context); + } +} \ No newline at end of file