From bdee0a5863a206b8cd22017544e72eb72dfa4f5d Mon Sep 17 00:00:00 2001 From: Mirko Da Corte Date: Sun, 12 Jul 2020 02:29:20 +0200 Subject: [PATCH 1/5] Started implementation of background migration tasks --- src/MongODM.Core/DbContext.cs | 18 +---- src/MongODM.Core/IDbContext.cs | 26 +++---- .../Migration/IMigrationManager.cs | 22 ++++++ .../Migration/MigrationManager.cs | 68 +++++++++++++++++++ .../Operations/MigrateOperation.cs | 65 ++++++++++++++++++ src/MongODM.Core/Tasks/IMigrateDbTask.cs | 10 +++ src/MongODM.Core/Tasks/MigrateDbTask.cs | 33 +++++++++ 7 files changed, 213 insertions(+), 29 deletions(-) create mode 100644 src/MongODM.Core/Migration/IMigrationManager.cs create mode 100644 src/MongODM.Core/Migration/MigrationManager.cs create mode 100644 src/MongODM.Core/Operations/MigrateOperation.cs create mode 100644 src/MongODM.Core/Tasks/IMigrateDbTask.cs create mode 100644 src/MongODM.Core/Tasks/MigrateDbTask.cs diff --git a/src/MongODM.Core/DbContext.cs b/src/MongODM.Core/DbContext.cs index 2ed8ede6..905d8969 100644 --- a/src/MongODM.Core/DbContext.cs +++ b/src/MongODM.Core/DbContext.cs @@ -90,32 +90,16 @@ public DbContext( public ICollectionRepository DbOperations { get; } public IDocumentSchemaRegister DocumentSchemaRegister { get; } public string Identifier { get; } - public bool IsMigrating { get; private set; } public SemanticVersion LibraryVersion { get; } + public virtual IEnumerable MigrationTaskList { get; } = Array.Empty(); public IProxyGenerator ProxyGenerator { get; } public IRepositoryRegister RepositoryRegister { get; } public ISerializerModifierAccessor SerializerModifierAccessor { get; } // Protected properties. - protected virtual IEnumerable MigrationTaskList { get; } = Array.Empty(); protected abstract IEnumerable ModelMapsCollectors { get; } // Methods. - public async Task MigrateRepositoriesAsync(CancellationToken cancellationToken = default) - { - IsMigrating = true; - - // Migrate collections. - foreach (var migration in MigrationTaskList) - await migration.MigrateAsync(cancellationToken).ConfigureAwait(false); - - // Build indexes. - foreach (var repository in RepositoryRegister.ModelCollectionRepositoryMap.Values) - await repository.BuildIndexesAsync(DocumentSchemaRegister, cancellationToken).ConfigureAwait(false); - - IsMigrating = false; - } - public virtual async Task SaveChangesAsync(CancellationToken cancellationToken = default) { /* diff --git a/src/MongODM.Core/IDbContext.cs b/src/MongODM.Core/IDbContext.cs index 8ba3be75..66e4e585 100644 --- a/src/MongODM.Core/IDbContext.cs +++ b/src/MongODM.Core/IDbContext.cs @@ -1,9 +1,12 @@ -using Etherna.MongODM.ProxyModels; +using Etherna.MongODM.Migration; +using Etherna.MongODM.Operations; +using Etherna.MongODM.ProxyModels; using Etherna.MongODM.Repositories; using Etherna.MongODM.Serialization; using Etherna.MongODM.Serialization.Modifiers; using Etherna.MongODM.Utility; using MongoDB.Driver; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; @@ -39,7 +42,12 @@ public interface IDbContext /// Database operator interested into maintenance tasks. /// IDbMaintainer DbMaintainer { get; } - + + /// + /// Internal collection for keep db operations execution log + /// + ICollectionRepository DbOperations { get; } + /// /// Container for model serialization and document schema information. /// @@ -51,14 +59,14 @@ public interface IDbContext string Identifier { get; } /// - /// Flag reporting eventual current migration operation. + /// Current MongODM library version /// - bool IsMigrating { get; } + SemanticVersion LibraryVersion { get; } /// - /// Current MongODM library version + /// List of registered migration tasks /// - SemanticVersion LibraryVersion { get; } + IEnumerable MigrationTaskList { get; } /// /// Current model proxy generator. @@ -76,12 +84,6 @@ public interface IDbContext ISerializerModifierAccessor SerializerModifierAccessor { get; } // Methods. - /// - /// Start a database migration process. - /// - /// Cancellation token - Task MigrateRepositoriesAsync(CancellationToken cancellationToken = default); - /// /// Save current model changes on db. /// diff --git a/src/MongODM.Core/Migration/IMigrationManager.cs b/src/MongODM.Core/Migration/IMigrationManager.cs new file mode 100644 index 00000000..7a3f2c2f --- /dev/null +++ b/src/MongODM.Core/Migration/IMigrationManager.cs @@ -0,0 +1,22 @@ +using Etherna.MongODM.Operations; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Etherna.MongODM.Migration +{ + internal interface IMigrationManager + { + Task IsMigrationRunningAsync(); + + Task> GetLastMigrationsAsync(int page, int take); + + Task GetMigrationAsync(string migrateOperationId); + + /// + /// Start a database migration process. + /// + /// Cancellation token + Task MigrateRepositoriesAsync(CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/src/MongODM.Core/Migration/MigrationManager.cs b/src/MongODM.Core/Migration/MigrationManager.cs new file mode 100644 index 00000000..7d4b6ece --- /dev/null +++ b/src/MongODM.Core/Migration/MigrationManager.cs @@ -0,0 +1,68 @@ +using Etherna.MongODM.Extensions; +using Etherna.MongODM.Operations; +using MongoDB.Driver; +using MongoDB.Driver.Linq; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Etherna.MongODM.Migration +{ + public class MigrationManager : IMigrationManager, IDbContextInitializable + { + // Fields. + private IDbContext dbContext = default!; + + // Constructor and initialization. + public void Initialize(IDbContext dbContext) + { + if (IsInitialized) + throw new InvalidOperationException("Instance already initialized"); + + this.dbContext = dbContext; + + IsInitialized = true; + } + + // Properties. + public bool IsInitialized { get; private set; } + + // Methods. + public async Task> GetLastMigrationsAsync(int page, int take) => + await dbContext.DbOperations.QueryElementsAsync(elements => + elements.OfType() + .PaginateDescending(r => r.CreationDateTime, page, take) + .ToListAsync()).ConfigureAwait(false); + + public async Task GetMigrationAsync(string migrateOperationId) + { + if (migrateOperationId is null) + throw new ArgumentNullException(nameof(migrateOperationId)); + + var migrateOp = await dbContext.DbOperations.QueryElementsAsync(elements => + elements.OfType() + .Where(op => op.Id == migrateOperationId) + .FirstAsync()).ConfigureAwait(false); + + return migrateOp; + } + + public async Task IsMigrationRunningAsync() + { + var migrateOp = await dbContext.DbOperations.QueryElementsAsync(elements => + elements.OfType() + .Where(op => op.DbContextName == dbContext.Identifier) + .Where(op => op.CurrentStatus == MigrateOperation.Status.Running) + .FirstOrDefaultAsync()).ConfigureAwait(false); + + return migrateOp; + } + + public Task MigrateRepositoriesAsync(CancellationToken cancellationToken = default) + { + // Run task. + throw new NotImplementedException(); + } + } +} diff --git a/src/MongODM.Core/Operations/MigrateOperation.cs b/src/MongODM.Core/Operations/MigrateOperation.cs new file mode 100644 index 00000000..1e3d0cce --- /dev/null +++ b/src/MongODM.Core/Operations/MigrateOperation.cs @@ -0,0 +1,65 @@ +using Etherna.MongODM.Attributes; +using System; + +namespace Etherna.MongODM.Operations +{ + public class MigrateOperation : OperationBase + { + // Enums. + public enum Status + { + New, + Running, + Completed, + Cancelled + } + + // Constructors. + public MigrateOperation(IDbContext owner, string? author) + : base(owner) + { + Author = author; + } + + // Properties. + public virtual string? Author { get; protected set; } + public virtual DateTime CompletedDateTime { get; protected set; } + public virtual Status CurrentStatus { get; protected set; } + public virtual string? TaskId { get; protected set; } + + // Methods. + [PropertyAlterer(nameof(CurrentStatus))] + public void TaskCancelled() + { + if (CurrentStatus == Status.Completed) + throw new InvalidOperationException(); + + CurrentStatus = Status.Cancelled; + } + + [PropertyAlterer(nameof(CompletedDateTime))] + [PropertyAlterer(nameof(CurrentStatus))] + public void TaskCompleted() + { + if (CurrentStatus != Status.Running) + throw new InvalidOperationException(); + + CompletedDateTime = DateTime.Now; + CurrentStatus = Status.Completed; + } + + [PropertyAlterer(nameof(CurrentStatus))] + [PropertyAlterer(nameof(TaskId))] + public void TaskStarted(string taskId) + { + if (taskId is null) + throw new ArgumentNullException(nameof(taskId)); + + if (CurrentStatus != Status.New) + throw new InvalidOperationException(); + + CurrentStatus = Status.Running; + TaskId = taskId; + } + } +} diff --git a/src/MongODM.Core/Tasks/IMigrateDbTask.cs b/src/MongODM.Core/Tasks/IMigrateDbTask.cs new file mode 100644 index 00000000..2a4afa21 --- /dev/null +++ b/src/MongODM.Core/Tasks/IMigrateDbTask.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace Etherna.MongODM.Tasks +{ + public interface IMigrateDbTask + { + Task RunAsync() + where TDbContext : class, IDbContext; + } +} \ No newline at end of file diff --git a/src/MongODM.Core/Tasks/MigrateDbTask.cs b/src/MongODM.Core/Tasks/MigrateDbTask.cs new file mode 100644 index 00000000..ba472c65 --- /dev/null +++ b/src/MongODM.Core/Tasks/MigrateDbTask.cs @@ -0,0 +1,33 @@ +using System; +using System.Threading.Tasks; + +namespace Etherna.MongODM.Tasks +{ + public class MigrateDbTask : IMigrateDbTask + { + // Fields. + private readonly IServiceProvider serviceProvider; + + // Constructors. + public MigrateDbTask( + IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + } + + // Methods. + public async Task RunAsync() + where TDbContext : class, IDbContext + { + var dbContext = (TDbContext)serviceProvider.GetService(typeof(TDbContext)); + + // Migrate collections. + foreach (var migration in dbContext.MigrationTaskList) + await migration.MigrateAsync(cancellationToken).ConfigureAwait(false); + + // Build indexes. + foreach (var repository in dbContext.RepositoryRegister.ModelCollectionRepositoryMap.Values) + await repository.BuildIndexesAsync(dbContext.DocumentSchemaRegister, cancellationToken).ConfigureAwait(false); + } + } +} From 3a9a56028a77e0dbfb931a14590737b147b72da7 Mon Sep 17 00:00:00 2001 From: Mirko Da Corte Date: Mon, 13 Jul 2020 02:01:37 +0200 Subject: [PATCH 2/5] Updating migration task --- .editorconfig | 3 ++ .../ServiceCollectionExtensions.cs | 5 +-- src/MongODM.Core/DbContext.cs | 10 +++--- src/MongODM.Core/IDbContext.cs | 9 ++++-- .../Operations/MigrateOperation.cs | 5 +-- src/MongODM.Core/Operations/OperationBase.cs | 8 ++--- .../Serializers/ExtendedClassMapSerializer.cs | 4 +-- ...rateDbTask.cs => IMigrateDbContextTask.cs} | 4 +-- src/MongODM.Core/Tasks/ITaskRunner.cs | 1 + ...grateDbTask.cs => MigrateDbContextTask.cs} | 14 ++++++--- .../Utility/{DBCache.cs => DbContextCache.cs} | 4 +-- .../Utility/DbContextDependencies.cs | 15 +++++---- ...DBMaintainer.cs => DbContextMaintainer.cs} | 4 +-- .../DbContextMigrationManager.cs} | 21 ++++++++----- .../{IDBCache.cs => IDbContextCache.cs} | 4 +-- .../Utility/IDbContextDependencies.cs | 5 +-- ...BMaintainer.cs => IDbContextMaintainer.cs} | 4 +-- .../IDbContextMigrationManager.cs} | 11 +++---- .../Tasks/HangfireTaskRunner.cs | 4 +++ .../Tasks/MigrateDbContextTaskFacade.cs | 31 +++++++++++++++++++ .../Tasks/UpdateDocDependenciesTaskFacade.cs | 2 -- .../ExtendedClassMapSerializerTest.cs | 4 +-- 22 files changed, 117 insertions(+), 55 deletions(-) rename src/MongODM.Core/Tasks/{IMigrateDbTask.cs => IMigrateDbContextTask.cs} (58%) rename src/MongODM.Core/Tasks/{MigrateDbTask.cs => MigrateDbContextTask.cs} (65%) rename src/MongODM.Core/Utility/{DBCache.cs => DbContextCache.cs} (95%) rename src/MongODM.Core/Utility/{DBMaintainer.cs => DbContextMaintainer.cs} (94%) rename src/MongODM.Core/{Migration/MigrationManager.cs => Utility/DbContextMigrationManager.cs} (76%) rename src/MongODM.Core/Utility/{IDBCache.cs => IDbContextCache.cs} (90%) rename src/MongODM.Core/Utility/{IDBMaintainer.cs => IDbContextMaintainer.cs} (78%) rename src/MongODM.Core/{Migration/IMigrationManager.cs => Utility/IDbContextMigrationManager.cs} (55%) create mode 100644 src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs diff --git a/.editorconfig b/.editorconfig index 24b71126..c545a099 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,6 +18,9 @@ dotnet_diagnostic.CA1303.severity = none # Don't need translated exceptions # CA1707: Identifiers should not contain underscores dotnet_diagnostic.CA1707.severity = none # I want to use underscore in constants +# CA1812: Avoid uninstantiated internal classes +dotnet_diagnostic.CA1812.severity = none # Doing extensive use of dependency injection + # CA1816: Dispose methods should call SuppressFinalize dotnet_diagnostic.CA1816.severity = none diff --git a/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs b/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs index dae9c683..f0961743 100644 --- a/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs +++ b/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs @@ -60,9 +60,10 @@ public static MongODMConfiguration UseMongODM(); + services.TryAddTransient(); services.TryAddTransient(); - services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); services.TryAddTransient(); services.TryAddTransient(); services.TryAddSingleton(); diff --git a/src/MongODM.Core/DbContext.cs b/src/MongODM.Core/DbContext.cs index 905d8969..fa838c80 100644 --- a/src/MongODM.Core/DbContext.cs +++ b/src/MongODM.Core/DbContext.cs @@ -34,8 +34,9 @@ public DbContext( throw new ArgumentNullException(nameof(options)); ApplicationVersion = options.ApplicationVersion; - DbCache = dependencies.DbCache; - DbMaintainer = dependencies.DbMaintainer; + DbCache = dependencies.DbContextCache; + DbMaintainer = dependencies.DbContextMaintainer; + DbContextMigrationManager = dependencies.DbContextMigrationManager; DbOperations = new CollectionRepository(options.DbOperationsCollectionName); DocumentSchemaRegister = dependencies.DocumentSchemaRegister; Identifier = options.Identifier ?? GetType().Name; @@ -85,8 +86,9 @@ public DbContext( .ToList(); public IMongoClient Client { get; } public IMongoDatabase Database { get; } - public IDbCache DbCache { get; } - public IDbMaintainer DbMaintainer { get; } + public IDbContextCache DbCache { get; } + public IDbContextMaintainer DbMaintainer { get; } + public IDbContextMigrationManager DbContextMigrationManager { get; } public ICollectionRepository DbOperations { get; } public IDocumentSchemaRegister DocumentSchemaRegister { get; } public string Identifier { get; } diff --git a/src/MongODM.Core/IDbContext.cs b/src/MongODM.Core/IDbContext.cs index 66e4e585..76caad34 100644 --- a/src/MongODM.Core/IDbContext.cs +++ b/src/MongODM.Core/IDbContext.cs @@ -36,12 +36,17 @@ public interface IDbContext /// /// Database cache container. /// - IDbCache DbCache { get; } + IDbContextCache DbCache { get; } /// /// Database operator interested into maintenance tasks. /// - IDbMaintainer DbMaintainer { get; } + IDbContextMaintainer DbMaintainer { get; } + + /// + /// Manage migrations over database context + /// + IDbContextMigrationManager DbContextMigrationManager { get; } /// /// Internal collection for keep db operations execution log diff --git a/src/MongODM.Core/Operations/MigrateOperation.cs b/src/MongODM.Core/Operations/MigrateOperation.cs index 1e3d0cce..194a5723 100644 --- a/src/MongODM.Core/Operations/MigrateOperation.cs +++ b/src/MongODM.Core/Operations/MigrateOperation.cs @@ -15,10 +15,11 @@ public enum Status } // Constructors. - public MigrateOperation(IDbContext owner, string? author) - : base(owner) + public MigrateOperation(IDbContext dbContext, string? author) + : base(dbContext) { Author = author; + CurrentStatus = Status.New; } // Properties. diff --git a/src/MongODM.Core/Operations/OperationBase.cs b/src/MongODM.Core/Operations/OperationBase.cs index 32861265..e8661da6 100644 --- a/src/MongODM.Core/Operations/OperationBase.cs +++ b/src/MongODM.Core/Operations/OperationBase.cs @@ -8,13 +8,13 @@ namespace Etherna.MongODM.Operations public abstract class OperationBase : IEntityModel { // Constructors and dispose. - public OperationBase(IDbContext owner) + public OperationBase(IDbContext dbContext) { - if (owner is null) - throw new ArgumentNullException(nameof(owner)); + if (dbContext is null) + throw new ArgumentNullException(nameof(dbContext)); CreationDateTime = DateTime.Now; - DbContextName = owner.Identifier; + DbContextName = dbContext.Identifier; } protected OperationBase() { } public void DisposeForDelete() { } diff --git a/src/MongODM.Core/Serialization/Serializers/ExtendedClassMapSerializer.cs b/src/MongODM.Core/Serialization/Serializers/ExtendedClassMapSerializer.cs index a4bc991d..cd201b0e 100644 --- a/src/MongODM.Core/Serialization/Serializers/ExtendedClassMapSerializer.cs +++ b/src/MongODM.Core/Serialization/Serializers/ExtendedClassMapSerializer.cs @@ -28,7 +28,7 @@ private struct ExtraElementCondition private readonly BsonElement documentVersionElement; // Fields. - private readonly IDbCache dbCache; + private readonly IDbContextCache dbCache; private readonly ISerializerModifierAccessor serializerModifierAccessor; private readonly ICollection extraElements; private readonly Func> fixDeserializedModelAsync; @@ -36,7 +36,7 @@ private struct ExtraElementCondition // Constructor. public ExtendedClassMapSerializer( - IDbCache dbCache, + IDbContextCache dbCache, SemanticVersion documentVersion, ISerializerModifierAccessor serializerModifierAccessor, Func>? fixDeserializedModelAsync = null) diff --git a/src/MongODM.Core/Tasks/IMigrateDbTask.cs b/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs similarity index 58% rename from src/MongODM.Core/Tasks/IMigrateDbTask.cs rename to src/MongODM.Core/Tasks/IMigrateDbContextTask.cs index 2a4afa21..b7b34b64 100644 --- a/src/MongODM.Core/Tasks/IMigrateDbTask.cs +++ b/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs @@ -2,9 +2,9 @@ namespace Etherna.MongODM.Tasks { - public interface IMigrateDbTask + public interface IMigrateDbContextTask { - Task RunAsync() + Task RunAsync(string authorId) where TDbContext : class, IDbContext; } } \ No newline at end of file diff --git a/src/MongODM.Core/Tasks/ITaskRunner.cs b/src/MongODM.Core/Tasks/ITaskRunner.cs index 51af70d0..32415ea5 100644 --- a/src/MongODM.Core/Tasks/ITaskRunner.cs +++ b/src/MongODM.Core/Tasks/ITaskRunner.cs @@ -5,6 +5,7 @@ namespace Etherna.MongODM.Tasks { public interface ITaskRunner { + void RunMigrateDbContextTask(Type dbContextType, string migrateOpId); void RunUpdateDocDependenciesTask(Type dbContextType, Type modelType, Type keyType, IEnumerable idPaths, object modelId); } } diff --git a/src/MongODM.Core/Tasks/MigrateDbTask.cs b/src/MongODM.Core/Tasks/MigrateDbContextTask.cs similarity index 65% rename from src/MongODM.Core/Tasks/MigrateDbTask.cs rename to src/MongODM.Core/Tasks/MigrateDbContextTask.cs index ba472c65..2739662b 100644 --- a/src/MongODM.Core/Tasks/MigrateDbTask.cs +++ b/src/MongODM.Core/Tasks/MigrateDbContextTask.cs @@ -1,25 +1,31 @@ -using System; +using Etherna.MongODM.Operations; +using System; using System.Threading.Tasks; namespace Etherna.MongODM.Tasks { - public class MigrateDbTask : IMigrateDbTask + public class MigrateDbContextTask : IMigrateDbContextTask { // Fields. private readonly IServiceProvider serviceProvider; // Constructors. - public MigrateDbTask( + public MigrateDbContextTask( IServiceProvider serviceProvider) { this.serviceProvider = serviceProvider; } // Methods. - public async Task RunAsync() + public async Task RunAsync(string migrateOpId) where TDbContext : class, IDbContext { var dbContext = (TDbContext)serviceProvider.GetService(typeof(TDbContext)); + var migrateOp = (MigrateOperation)await dbContext.DbOperations.FindOneAsync(migrateOpId).ConfigureAwait(false); + + // Start migrate operation. + migrateOp.TaskStarted(); + await dbContext.SaveChangesAsync().ConfigureAwait(false); // Migrate collections. foreach (var migration in dbContext.MigrationTaskList) diff --git a/src/MongODM.Core/Utility/DBCache.cs b/src/MongODM.Core/Utility/DbContextCache.cs similarity index 95% rename from src/MongODM.Core/Utility/DBCache.cs rename to src/MongODM.Core/Utility/DbContextCache.cs index 6eaa5b7d..20c7065b 100644 --- a/src/MongODM.Core/Utility/DBCache.cs +++ b/src/MongODM.Core/Utility/DbContextCache.cs @@ -5,7 +5,7 @@ namespace Etherna.MongODM.Utility { - public class DbCache : IDbCache + public class DbContextCache : IDbContextCache { // Consts. private const string CacheKey = "DBCache"; @@ -14,7 +14,7 @@ public class DbCache : IDbCache private readonly IExecutionContext executionContext; // Constructors. - public DbCache(IExecutionContext executionContext) + public DbContextCache(IExecutionContext executionContext) { this.executionContext = executionContext ?? throw new ArgumentNullException(nameof(executionContext)); } diff --git a/src/MongODM.Core/Utility/DbContextDependencies.cs b/src/MongODM.Core/Utility/DbContextDependencies.cs index 03b90883..c108da6d 100644 --- a/src/MongODM.Core/Utility/DbContextDependencies.cs +++ b/src/MongODM.Core/Utility/DbContextDependencies.cs @@ -8,8 +8,9 @@ namespace Etherna.MongODM.Utility public class DbContextDependencies : IDbContextDependencies { public DbContextDependencies( - IDbCache dbCache, - IDbMaintainer dbMaintainer, + IDbContextCache dbCache, + IDbContextMaintainer dbMaintainer, + IDbContextMigrationManager dbContextMigrationManager, IDocumentSchemaRegister documentSchemaRegister, IProxyGenerator proxyGenerator, IRepositoryRegister repositoryRegister, @@ -20,16 +21,18 @@ public DbContextDependencies( #pragma warning restore CA1801 // Review unused parameters #pragma warning restore IDE0060 // Remove unused parameter { - DbCache = dbCache; - DbMaintainer = dbMaintainer; + DbContextCache = dbCache; + DbContextMaintainer = dbMaintainer; + DbContextMigrationManager = dbContextMigrationManager; DocumentSchemaRegister = documentSchemaRegister; ProxyGenerator = proxyGenerator; RepositoryRegister = repositoryRegister; SerializerModifierAccessor = serializerModifierAccessor; } - public IDbCache DbCache { get; } - public IDbMaintainer DbMaintainer { get; } + public IDbContextCache DbContextCache { get; } + public IDbContextMaintainer DbContextMaintainer { get; } + public IDbContextMigrationManager DbContextMigrationManager { get; } public IDocumentSchemaRegister DocumentSchemaRegister { get; } public IProxyGenerator ProxyGenerator { get; } public IRepositoryRegister RepositoryRegister { get; } diff --git a/src/MongODM.Core/Utility/DBMaintainer.cs b/src/MongODM.Core/Utility/DbContextMaintainer.cs similarity index 94% rename from src/MongODM.Core/Utility/DBMaintainer.cs rename to src/MongODM.Core/Utility/DbContextMaintainer.cs index e871015a..9e838a08 100644 --- a/src/MongODM.Core/Utility/DBMaintainer.cs +++ b/src/MongODM.Core/Utility/DbContextMaintainer.cs @@ -6,14 +6,14 @@ namespace Etherna.MongODM.Utility { - public class DbMaintainer : IDbMaintainer + public class DbContextMaintainer : IDbContextMaintainer { // Fields. private IDbContext dbContext = default!; private readonly ITaskRunner taskRunner; // Constructors and initialization. - public DbMaintainer(ITaskRunner taskRunner) + public DbContextMaintainer(ITaskRunner taskRunner) { this.taskRunner = taskRunner; } diff --git a/src/MongODM.Core/Migration/MigrationManager.cs b/src/MongODM.Core/Utility/DbContextMigrationManager.cs similarity index 76% rename from src/MongODM.Core/Migration/MigrationManager.cs rename to src/MongODM.Core/Utility/DbContextMigrationManager.cs index 7d4b6ece..dd9afe1d 100644 --- a/src/MongODM.Core/Migration/MigrationManager.cs +++ b/src/MongODM.Core/Utility/DbContextMigrationManager.cs @@ -1,20 +1,25 @@ using Etherna.MongODM.Extensions; using Etherna.MongODM.Operations; +using Etherna.MongODM.Tasks; using MongoDB.Driver; using MongoDB.Driver.Linq; using System; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; -namespace Etherna.MongODM.Migration +namespace Etherna.MongODM.Utility { - public class MigrationManager : IMigrationManager, IDbContextInitializable + public class DbContextMigrationManager : IDbContextMigrationManager, IDbContextInitializable { // Fields. private IDbContext dbContext = default!; - + private readonly ITaskRunner taskRunner; + // Constructor and initialization. + public DbContextMigrationManager(ITaskRunner taskRunner) + { + this.taskRunner = taskRunner; + } public void Initialize(IDbContext dbContext) { if (IsInitialized) @@ -59,10 +64,12 @@ public async Task GetMigrationAsync(string migrateOperationId) return migrateOp; } - public Task MigrateRepositoriesAsync(CancellationToken cancellationToken = default) + public async Task StartDbContextMigrationAsync(string authorId) { - // Run task. - throw new NotImplementedException(); + var migrateOp = new MigrateOperation(dbContext, authorId); + await dbContext.DbOperations.CreateAsync(migrateOp).ConfigureAwait(false); + + taskRunner.RunMigrateDbContextTask(dbContext.GetType(), migrateOp.Id); } } } diff --git a/src/MongODM.Core/Utility/IDBCache.cs b/src/MongODM.Core/Utility/IDbContextCache.cs similarity index 90% rename from src/MongODM.Core/Utility/IDBCache.cs rename to src/MongODM.Core/Utility/IDbContextCache.cs index 7979c869..a1832174 100644 --- a/src/MongODM.Core/Utility/IDBCache.cs +++ b/src/MongODM.Core/Utility/IDbContextCache.cs @@ -4,9 +4,9 @@ namespace Etherna.MongODM.Utility { /// - /// Interface for implementation. + /// Interface for implementation. /// - public interface IDbCache + public interface IDbContextCache { // Properties. /// diff --git a/src/MongODM.Core/Utility/IDbContextDependencies.cs b/src/MongODM.Core/Utility/IDbContextDependencies.cs index bc8d335b..f362e8ad 100644 --- a/src/MongODM.Core/Utility/IDbContextDependencies.cs +++ b/src/MongODM.Core/Utility/IDbContextDependencies.cs @@ -7,8 +7,9 @@ namespace Etherna.MongODM.Utility { public interface IDbContextDependencies { - IDbCache DbCache { get; } - IDbMaintainer DbMaintainer { get; } + IDbContextCache DbContextCache { get; } + IDbContextMaintainer DbContextMaintainer { get; } + IDbContextMigrationManager DbContextMigrationManager { get; } IDocumentSchemaRegister DocumentSchemaRegister { get; } IProxyGenerator ProxyGenerator { get; } IRepositoryRegister RepositoryRegister { get; } diff --git a/src/MongODM.Core/Utility/IDBMaintainer.cs b/src/MongODM.Core/Utility/IDbContextMaintainer.cs similarity index 78% rename from src/MongODM.Core/Utility/IDBMaintainer.cs rename to src/MongODM.Core/Utility/IDbContextMaintainer.cs index db9c9da3..770e6449 100644 --- a/src/MongODM.Core/Utility/IDBMaintainer.cs +++ b/src/MongODM.Core/Utility/IDbContextMaintainer.cs @@ -3,9 +3,9 @@ namespace Etherna.MongODM.Utility { /// - /// Interface for implementation. + /// Interface for implementation. /// - public interface IDbMaintainer : IDbContextInitializable + public interface IDbContextMaintainer : IDbContextInitializable { // Methods. /// diff --git a/src/MongODM.Core/Migration/IMigrationManager.cs b/src/MongODM.Core/Utility/IDbContextMigrationManager.cs similarity index 55% rename from src/MongODM.Core/Migration/IMigrationManager.cs rename to src/MongODM.Core/Utility/IDbContextMigrationManager.cs index 7a3f2c2f..a9298212 100644 --- a/src/MongODM.Core/Migration/IMigrationManager.cs +++ b/src/MongODM.Core/Utility/IDbContextMigrationManager.cs @@ -1,11 +1,10 @@ using Etherna.MongODM.Operations; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; -namespace Etherna.MongODM.Migration +namespace Etherna.MongODM.Utility { - internal interface IMigrationManager + public interface IDbContextMigrationManager { Task IsMigrationRunningAsync(); @@ -14,9 +13,9 @@ internal interface IMigrationManager Task GetMigrationAsync(string migrateOperationId); /// - /// Start a database migration process. + /// Start a db context migration process. /// - /// Cancellation token - Task MigrateRepositoriesAsync(CancellationToken cancellationToken = default); + /// Id of user requiring the migration + Task StartDbContextMigrationAsync(string authorId); } } \ No newline at end of file diff --git a/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs b/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs index d86d0da9..1b069a0d 100644 --- a/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs +++ b/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs @@ -24,6 +24,10 @@ public HangfireTaskRunner( } // Methods. + public void RunMigrateDbContextTask(Type dbContextType, string migrateOpId) => + backgroundJobClient.Enqueue( + task => task.RunAsync(dbContextType, migrateOpId)); + public void RunUpdateDocDependenciesTask(Type dbContextType, Type modelType, Type keyType, IEnumerable idPaths, object modelId) => backgroundJobClient.Enqueue( task => task.RunAsync(dbContextType, modelType, keyType, idPaths, modelId)); diff --git a/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs b/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs new file mode 100644 index 00000000..4b304b0e --- /dev/null +++ b/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs @@ -0,0 +1,31 @@ +using Etherna.MongODM.Tasks; +using Hangfire; +using System; +using System.Reflection; +using System.Threading.Tasks; + +namespace Etherna.MongODM.HF.Tasks +{ + class MigrateDbContextTaskFacade + { + // Fields. + private readonly IMigrateDbContextTask task; + + // Constructors. + public MigrateDbContextTaskFacade(IMigrateDbContextTask task) + { + this.task = task; + } + + // Methods. + [Queue(Queues.DB_MAINTENANCE)] + public Task RunAsync(Type dbContextType, string migrateOpId) + { + var method = typeof(MigrateDbContextTask).GetMethod( + nameof(MigrateDbContextTask.RunAsync), BindingFlags.Public | BindingFlags.Instance) + .MakeGenericMethod(dbContextType); + + return (Task)method.Invoke(task, new object[] { migrateOpId }); + } + } +} diff --git a/src/MongODM.Hangfire/Tasks/UpdateDocDependenciesTaskFacade.cs b/src/MongODM.Hangfire/Tasks/UpdateDocDependenciesTaskFacade.cs index 16644c88..95139ac1 100644 --- a/src/MongODM.Hangfire/Tasks/UpdateDocDependenciesTaskFacade.cs +++ b/src/MongODM.Hangfire/Tasks/UpdateDocDependenciesTaskFacade.cs @@ -2,13 +2,11 @@ using Hangfire; using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Threading.Tasks; namespace Etherna.MongODM.HF.Tasks { - [SuppressMessage("Performance", "CA1812:Avoid uninstantiated internal classes", Justification = "It is instantiated by Hangfire")] class UpdateDocDependenciesTaskFacade { // Fields. diff --git a/test/MongODM.Core.Tests/ExtendedClassMapSerializerTest.cs b/test/MongODM.Core.Tests/ExtendedClassMapSerializerTest.cs index 5e8ab713..7230c977 100644 --- a/test/MongODM.Core.Tests/ExtendedClassMapSerializerTest.cs +++ b/test/MongODM.Core.Tests/ExtendedClassMapSerializerTest.cs @@ -65,14 +65,14 @@ public SerializationTestElement( } // Fields. - private readonly Mock dbCacheMock; + private readonly Mock dbCacheMock; private readonly SemanticVersion documentVersion = new SemanticVersion("1.0.0"); private readonly Mock serializerModifierAccessorMock; // Constructor. public ExtendedClassMapSerializerTest() { - dbCacheMock = new Mock(); + dbCacheMock = new Mock(); dbCacheMock.Setup(c => c.LoadedModels.ContainsKey(It.IsAny())) .Returns(() => false); From b20cb598cc48c7a2ca08e6b484c787cd0c0265f3 Mon Sep 17 00:00:00 2001 From: Mirko Da Corte Date: Mon, 13 Jul 2020 19:30:43 +0200 Subject: [PATCH 3/5] Updating background migration --- .../StaticConfigurationBuilder.cs | 4 +- src/MongODM.Core/DbContext.cs | 4 +- src/MongODM.Core/IDbContext.cs | 2 +- src/MongODM.Core/Migration/MigrationResult.cs | 26 +++++++++++ .../Migration/MongoCollectionMigration.cs | 12 ++++- .../Migration/MongoDocumentMigration.cs | 15 ++++-- .../Migration/MongoMigrationBase.cs | 21 ++++++++- .../Models/Internal/EntityModelBase.cs | 46 +++++++++++++++++++ .../MigrateOpAgg/MigrateExecutionLog.cs | 38 +++++++++++++++ .../Internal}/MigrateOperation.cs | 28 +++++++++-- src/MongODM.Core/Models/Internal/ModelBase.cs | 11 +++++ .../ModelMaps/MigrateExecutionLogMap.cs | 14 ++++++ .../Internal}/ModelMaps/OperationBaseMap.cs | 2 +- .../Models/Internal/OperationBase.cs | 21 +++++++++ .../Internal}/SeedOperation.cs | 2 +- src/MongODM.Core/Operations/OperationBase.cs | 30 ------------ .../Tasks/IMigrateDbContextTask.cs | 2 +- .../Tasks/MigrateDbContextTask.cs | 35 ++++++++++++-- .../Utility/DbContextMigrationManager.cs | 2 +- .../Utility/IDbContextMigrationManager.cs | 2 +- .../Tasks/HangfireTaskRunner.cs | 2 +- .../Tasks/MigrateDbContextTaskFacade.cs | 5 +- 22 files changed, 264 insertions(+), 60 deletions(-) create mode 100644 src/MongODM.Core/Migration/MigrationResult.cs create mode 100644 src/MongODM.Core/Models/Internal/EntityModelBase.cs create mode 100644 src/MongODM.Core/Models/Internal/MigrateOpAgg/MigrateExecutionLog.cs rename src/MongODM.Core/{Operations => Models/Internal}/MigrateOperation.cs (66%) create mode 100644 src/MongODM.Core/Models/Internal/ModelBase.cs create mode 100644 src/MongODM.Core/Models/Internal/ModelMaps/MigrateExecutionLogMap.cs rename src/MongODM.Core/{Operations => Models/Internal}/ModelMaps/OperationBaseMap.cs (95%) create mode 100644 src/MongODM.Core/Models/Internal/OperationBase.cs rename src/MongODM.Core/{Operations => Models/Internal}/SeedOperation.cs (82%) delete mode 100644 src/MongODM.Core/Operations/OperationBase.cs diff --git a/src/MongODM.AspNetCore/StaticConfigurationBuilder.cs b/src/MongODM.AspNetCore/StaticConfigurationBuilder.cs index f0389ab6..4ab051a2 100644 --- a/src/MongODM.AspNetCore/StaticConfigurationBuilder.cs +++ b/src/MongODM.AspNetCore/StaticConfigurationBuilder.cs @@ -1,5 +1,5 @@ using Etherna.MongODM.Conventions; -using Etherna.MongODM.Operations; +using Etherna.MongODM.Models.Internal; using Etherna.MongODM.ProxyModels; using Etherna.MongODM.Utility; using MongoDB.Bson; @@ -20,7 +20,7 @@ public StaticConfigurationBuilder(IProxyGenerator proxyGenerator) BsonSerializer.RegisterDiscriminatorConvention(typeof(TModelBase), new HierarchicalProxyTolerantDiscriminatorConvention("_t", proxyGenerator)); - BsonSerializer.RegisterDiscriminatorConvention(typeof(OperationBase), + BsonSerializer.RegisterDiscriminatorConvention(typeof(EntityModelBase), new HierarchicalProxyTolerantDiscriminatorConvention("_t", proxyGenerator)); } } diff --git a/src/MongODM.Core/DbContext.cs b/src/MongODM.Core/DbContext.cs index fa838c80..94bbcd43 100644 --- a/src/MongODM.Core/DbContext.cs +++ b/src/MongODM.Core/DbContext.cs @@ -1,7 +1,7 @@ using Etherna.MongODM.Migration; using Etherna.MongODM.Models; -using Etherna.MongODM.Operations; -using Etherna.MongODM.Operations.ModelMaps; +using Etherna.MongODM.Models.Internal; +using Etherna.MongODM.Models.Internal.ModelMaps; using Etherna.MongODM.ProxyModels; using Etherna.MongODM.Repositories; using Etherna.MongODM.Serialization; diff --git a/src/MongODM.Core/IDbContext.cs b/src/MongODM.Core/IDbContext.cs index 76caad34..7e004769 100644 --- a/src/MongODM.Core/IDbContext.cs +++ b/src/MongODM.Core/IDbContext.cs @@ -1,5 +1,5 @@ using Etherna.MongODM.Migration; -using Etherna.MongODM.Operations; +using Etherna.MongODM.Models.Internal; using Etherna.MongODM.ProxyModels; using Etherna.MongODM.Repositories; using Etherna.MongODM.Serialization; diff --git a/src/MongODM.Core/Migration/MigrationResult.cs b/src/MongODM.Core/Migration/MigrationResult.cs new file mode 100644 index 00000000..8b2f276d --- /dev/null +++ b/src/MongODM.Core/Migration/MigrationResult.cs @@ -0,0 +1,26 @@ +namespace Etherna.MongODM.Migration +{ + public class MigrationResult + { + // Constructors. + private MigrationResult() { } + + // Properties. + public bool Succeded { get; private set; } + public long MigratedDocuments { get; private set; } + + // Methods. + public static MigrationResult Failed() => + new MigrationResult + { + Succeded = false + }; + + public static MigrationResult Succeeded(long migratedDocuments) => + new MigrationResult + { + Succeded = true, + MigratedDocuments = migratedDocuments + }; + } +} \ No newline at end of file diff --git a/src/MongODM.Core/Migration/MongoCollectionMigration.cs b/src/MongODM.Core/Migration/MongoCollectionMigration.cs index 00040e3d..f2033432 100644 --- a/src/MongODM.Core/Migration/MongoCollectionMigration.cs +++ b/src/MongODM.Core/Migration/MongoCollectionMigration.cs @@ -18,16 +18,20 @@ public class MongoCollectionMigration where TModelDest : class, IEntityModel { + // Fields. private readonly Func converter; private readonly Func discriminator; private readonly IMongoCollection destinationCollection; private readonly IMongoCollection sourceCollection; + // Constructor. public MongoCollectionMigration( ICollectionRepository sourceCollection, ICollectionRepository destinationCollection, Func converter, - Func discriminator) + Func discriminator, + string id) + : base(id) { if (sourceCollection is null) throw new ArgumentNullException(nameof(sourceCollection)); @@ -40,7 +44,11 @@ public MongoCollectionMigration( this.discriminator = discriminator; } - public override Task MigrateAsync(CancellationToken cancellationToken = default) => + // Methods. + public override Task MigrateAsync( + int callbackEveryDocuments = 0, + Func? callbackAsync = null, + CancellationToken cancellationToken = default) => sourceCollection.Find(Builders.Filter.Empty, new FindOptions { NoCursorTimeout = true }) .ForEachAsync(obj => { diff --git a/src/MongODM.Core/Migration/MongoDocumentMigration.cs b/src/MongODM.Core/Migration/MongoDocumentMigration.cs index 5c8c4731..3a3ea97f 100644 --- a/src/MongODM.Core/Migration/MongoDocumentMigration.cs +++ b/src/MongODM.Core/Migration/MongoDocumentMigration.cs @@ -17,12 +17,16 @@ namespace Etherna.MongODM.Migration public class MongoDocumentMigration : MongoMigrationBase where TModel : class, IEntityModel { + // Fields. private readonly SemanticVersion minimumDocumentVersion; private readonly IMongoCollection sourceCollection; + // Constructors. public MongoDocumentMigration( ICollectionRepository sourceCollection, - SemanticVersion minimumDocumentVersion) + SemanticVersion minimumDocumentVersion, + string id) + : base(id) { if (sourceCollection is null) throw new ArgumentNullException(nameof(sourceCollection)); @@ -31,10 +35,11 @@ public MongoDocumentMigration( this.minimumDocumentVersion = minimumDocumentVersion; } - /// - /// Fix all documents prev of MinimumDocumentVersion - /// - public override async Task MigrateAsync(CancellationToken cancellationToken = default) + // Methods. + public override async Task MigrateAsync( + int callbackEveryDocuments = 0, + Func? callbackAsync = null, + CancellationToken cancellationToken = default) { var filterBuilder = Builders.Filter; var filter = filterBuilder.Or( diff --git a/src/MongODM.Core/Migration/MongoMigrationBase.cs b/src/MongODM.Core/Migration/MongoMigrationBase.cs index 53a67fdc..1643880e 100644 --- a/src/MongODM.Core/Migration/MongoMigrationBase.cs +++ b/src/MongODM.Core/Migration/MongoMigrationBase.cs @@ -1,10 +1,27 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; namespace Etherna.MongODM.Migration { public abstract class MongoMigrationBase { - public abstract Task MigrateAsync(CancellationToken cancellationToken = default); + // Constructors. + public MongoMigrationBase(string id) + { + Id = id ?? throw new ArgumentNullException(nameof(id)); + } + + // Properties. + public string Id { get; } + + // Methods. + /// + /// Perform migration with optional updating callback + /// + /// Interval of processed documents between callback invokations. 0 if ignore callback + /// The async callback function. Parameter is number of processed documents + /// The migration result + public abstract Task MigrateAsync(int callbackEveryDocuments = 0, Func? callbackAsync = null, CancellationToken cancellationToken = default); } } diff --git a/src/MongODM.Core/Models/Internal/EntityModelBase.cs b/src/MongODM.Core/Models/Internal/EntityModelBase.cs new file mode 100644 index 00000000..4761fe39 --- /dev/null +++ b/src/MongODM.Core/Models/Internal/EntityModelBase.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + +namespace Etherna.MongODM.Models.Internal +{ + public abstract class EntityModelBase : ModelBase, IEntityModel + { + private DateTime _creationDateTime; + + // Constructors and dispose. + protected EntityModelBase() + { + _creationDateTime = DateTime.Now; + } + + public virtual void DisposeForDelete() { } + + // Properties. + public virtual DateTime CreationDateTime { get => _creationDateTime; protected set => _creationDateTime = value; } + } + + public abstract class EntityModelBase : EntityModelBase, IEntityModel + { + // Properties. + public virtual TKey Id { get; protected set; } = default!; + + // Methods. + public override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) return true; + if (obj is null) return false; + if (EqualityComparer.Default.Equals(Id, default!) || + !(obj is IEntityModel) || + EqualityComparer.Default.Equals((obj as IEntityModel)!.Id, default!)) return false; + return GetType() == obj.GetType() && + EqualityComparer.Default.Equals(Id, (obj as IEntityModel)!.Id); + } + + public override int GetHashCode() + { + if (EqualityComparer.Default.Equals(Id, default!)) + return -1; + return Id!.GetHashCode(); + } + } +} diff --git a/src/MongODM.Core/Models/Internal/MigrateOpAgg/MigrateExecutionLog.cs b/src/MongODM.Core/Models/Internal/MigrateOpAgg/MigrateExecutionLog.cs new file mode 100644 index 00000000..6887532b --- /dev/null +++ b/src/MongODM.Core/Models/Internal/MigrateOpAgg/MigrateExecutionLog.cs @@ -0,0 +1,38 @@ +using System; + +namespace Etherna.MongODM.Models.Internal.MigrateOpAgg +{ + public class MigrateExecutionLog : ModelBase + { + // Enums. + public enum ExecutionState + { + Executing, + Succeded, + Skipped, + Failed + } + + // Constructors. + public MigrateExecutionLog( + ExecutionState action, + string migrationId, + string migrationType, + long totMigratedDocs) + { + Action = action; + CreationDateTime = DateTime.Now; + MigrationId = migrationId; + MigrationType = migrationType; + TotMigratedDocs = totMigratedDocs; + } + protected MigrateExecutionLog() { } + + // Properties. + public virtual ExecutionState Action { get; protected set; } + public virtual DateTime CreationDateTime { get; protected set; } + public virtual string MigrationId { get; protected set; } = default!; + public string MigrationType { get; } = default!; + public long TotMigratedDocs { get; protected set; } + } +} diff --git a/src/MongODM.Core/Operations/MigrateOperation.cs b/src/MongODM.Core/Models/Internal/MigrateOperation.cs similarity index 66% rename from src/MongODM.Core/Operations/MigrateOperation.cs rename to src/MongODM.Core/Models/Internal/MigrateOperation.cs index 194a5723..9486b579 100644 --- a/src/MongODM.Core/Operations/MigrateOperation.cs +++ b/src/MongODM.Core/Models/Internal/MigrateOperation.cs @@ -1,7 +1,9 @@ using Etherna.MongODM.Attributes; +using Etherna.MongODM.Models.Internal.MigrateOpAgg; using System; +using System.Collections.Generic; -namespace Etherna.MongODM.Operations +namespace Etherna.MongODM.Models.Internal { public class MigrateOperation : OperationBase { @@ -14,6 +16,9 @@ public enum Status Cancelled } + // Fields. + private List _logs = new List(); + // Constructors. public MigrateOperation(IDbContext dbContext, string? author) : base(dbContext) @@ -21,16 +26,31 @@ public MigrateOperation(IDbContext dbContext, string? author) Author = author; CurrentStatus = Status.New; } + protected MigrateOperation() { } // Properties. public virtual string? Author { get; protected set; } public virtual DateTime CompletedDateTime { get; protected set; } public virtual Status CurrentStatus { get; protected set; } + public virtual IEnumerable Logs + { + get => _logs; + protected set => _logs = new List(value ?? Array.Empty()); + } public virtual string? TaskId { get; protected set; } // Methods. + [PropertyAlterer(nameof(Logs))] + public virtual void AddLog(MigrateExecutionLog log) + { + if (log is null) + throw new ArgumentNullException(nameof(log)); + + _logs.Add(log); + } + [PropertyAlterer(nameof(CurrentStatus))] - public void TaskCancelled() + public virtual void TaskCancelled() { if (CurrentStatus == Status.Completed) throw new InvalidOperationException(); @@ -40,7 +60,7 @@ public void TaskCancelled() [PropertyAlterer(nameof(CompletedDateTime))] [PropertyAlterer(nameof(CurrentStatus))] - public void TaskCompleted() + public virtual void TaskCompleted() { if (CurrentStatus != Status.Running) throw new InvalidOperationException(); @@ -51,7 +71,7 @@ public void TaskCompleted() [PropertyAlterer(nameof(CurrentStatus))] [PropertyAlterer(nameof(TaskId))] - public void TaskStarted(string taskId) + public virtual void TaskStarted(string taskId) { if (taskId is null) throw new ArgumentNullException(nameof(taskId)); diff --git a/src/MongODM.Core/Models/Internal/ModelBase.cs b/src/MongODM.Core/Models/Internal/ModelBase.cs new file mode 100644 index 00000000..4ac98839 --- /dev/null +++ b/src/MongODM.Core/Models/Internal/ModelBase.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace Etherna.MongODM.Models.Internal +{ + public abstract class ModelBase : IModel + { + [SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Setter needed for deserialization scope")] + public virtual IDictionary? ExtraElements { get; protected set; } + } +} diff --git a/src/MongODM.Core/Models/Internal/ModelMaps/MigrateExecutionLogMap.cs b/src/MongODM.Core/Models/Internal/ModelMaps/MigrateExecutionLogMap.cs new file mode 100644 index 00000000..d6a4795a --- /dev/null +++ b/src/MongODM.Core/Models/Internal/ModelMaps/MigrateExecutionLogMap.cs @@ -0,0 +1,14 @@ +using Etherna.MongODM.Models.Internal.MigrateOpAgg; +using Etherna.MongODM.Serialization; + +namespace Etherna.MongODM.Models.Internal.ModelMaps +{ + class MigrateExecutionLogMap : IModelMapsCollector + { + public void Register(IDbContext dbContext) + { + dbContext.DocumentSchemaRegister.RegisterModelSchema( + "0.20.0"); //mongodm library's version + } + } +} diff --git a/src/MongODM.Core/Operations/ModelMaps/OperationBaseMap.cs b/src/MongODM.Core/Models/Internal/ModelMaps/OperationBaseMap.cs similarity index 95% rename from src/MongODM.Core/Operations/ModelMaps/OperationBaseMap.cs rename to src/MongODM.Core/Models/Internal/ModelMaps/OperationBaseMap.cs index 479276ea..6a4be08d 100644 --- a/src/MongODM.Core/Operations/ModelMaps/OperationBaseMap.cs +++ b/src/MongODM.Core/Models/Internal/ModelMaps/OperationBaseMap.cs @@ -4,7 +4,7 @@ using MongoDB.Bson.Serialization.IdGenerators; using MongoDB.Bson.Serialization.Serializers; -namespace Etherna.MongODM.Operations.ModelMaps +namespace Etherna.MongODM.Models.Internal.ModelMaps { class OperationBaseMap : IModelMapsCollector { diff --git a/src/MongODM.Core/Models/Internal/OperationBase.cs b/src/MongODM.Core/Models/Internal/OperationBase.cs new file mode 100644 index 00000000..fa3f258a --- /dev/null +++ b/src/MongODM.Core/Models/Internal/OperationBase.cs @@ -0,0 +1,21 @@ +using System; + +namespace Etherna.MongODM.Models.Internal +{ + public abstract class OperationBase : EntityModelBase + { + // Constructors and dispose. + public OperationBase(IDbContext dbContext) + { + if (dbContext is null) + throw new ArgumentNullException(nameof(dbContext)); + + CreationDateTime = DateTime.Now; + DbContextName = dbContext.Identifier; + } + protected OperationBase() { } + + // Properties. + public virtual string DbContextName { get; protected set; } = default!; + } +} diff --git a/src/MongODM.Core/Operations/SeedOperation.cs b/src/MongODM.Core/Models/Internal/SeedOperation.cs similarity index 82% rename from src/MongODM.Core/Operations/SeedOperation.cs rename to src/MongODM.Core/Models/Internal/SeedOperation.cs index dd54cd51..9ed838e8 100644 --- a/src/MongODM.Core/Operations/SeedOperation.cs +++ b/src/MongODM.Core/Models/Internal/SeedOperation.cs @@ -1,4 +1,4 @@ -namespace Etherna.MongODM.Operations +namespace Etherna.MongODM.Models.Internal { public class SeedOperation : OperationBase { diff --git a/src/MongODM.Core/Operations/OperationBase.cs b/src/MongODM.Core/Operations/OperationBase.cs deleted file mode 100644 index e8661da6..00000000 --- a/src/MongODM.Core/Operations/OperationBase.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Etherna.MongODM.Models; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -namespace Etherna.MongODM.Operations -{ - public abstract class OperationBase : IEntityModel - { - // Constructors and dispose. - public OperationBase(IDbContext dbContext) - { - if (dbContext is null) - throw new ArgumentNullException(nameof(dbContext)); - - CreationDateTime = DateTime.Now; - DbContextName = dbContext.Identifier; - } - protected OperationBase() { } - public void DisposeForDelete() { } - - // Properties. - public virtual string Id { get; protected set; } = default!; - public virtual DateTime CreationDateTime { get; protected set; } - public virtual string DbContextName { get; protected set; } = default!; - - [SuppressMessage("Usage", "CA2227:Collection properties should be read only", Justification = "Setter needed for deserialization scope")] - public virtual IDictionary? ExtraElements { get; protected set; } - } -} diff --git a/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs b/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs index b7b34b64..c1068187 100644 --- a/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs +++ b/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs @@ -4,7 +4,7 @@ namespace Etherna.MongODM.Tasks { public interface IMigrateDbContextTask { - Task RunAsync(string authorId) + Task RunAsync(string authorId, string taskId) where TDbContext : class, IDbContext; } } \ No newline at end of file diff --git a/src/MongODM.Core/Tasks/MigrateDbContextTask.cs b/src/MongODM.Core/Tasks/MigrateDbContextTask.cs index 2739662b..337deb6c 100644 --- a/src/MongODM.Core/Tasks/MigrateDbContextTask.cs +++ b/src/MongODM.Core/Tasks/MigrateDbContextTask.cs @@ -1,4 +1,5 @@ -using Etherna.MongODM.Operations; +using Etherna.MongODM.Models.Internal; +using Etherna.MongODM.Models.Internal.MigrateOpAgg; using System; using System.Threading.Tasks; @@ -17,19 +18,45 @@ public MigrateDbContextTask( } // Methods. - public async Task RunAsync(string migrateOpId) + public async Task RunAsync(string migrateOpId, string taskId) where TDbContext : class, IDbContext { var dbContext = (TDbContext)serviceProvider.GetService(typeof(TDbContext)); var migrateOp = (MigrateOperation)await dbContext.DbOperations.FindOneAsync(migrateOpId).ConfigureAwait(false); // Start migrate operation. - migrateOp.TaskStarted(); + migrateOp.TaskStarted(taskId); await dbContext.SaveChangesAsync().ConfigureAwait(false); // Migrate collections. foreach (var migration in dbContext.MigrationTaskList) - await migration.MigrateAsync(cancellationToken).ConfigureAwait(false); + { + var migrationType = migration.GetType().Name; + + //running migration + var result = await migration.MigrateAsync(500, + async procDocs => + { + migrateOp.AddLog(new MigrateExecutionLog( + MigrateExecutionLog.ExecutionState.Executing, + migration.Id, + migrationType, + procDocs)); + + await dbContext.SaveChangesAsync().ConfigureAwait(false); + }).ConfigureAwait(false); + + //ended migration log + migrateOp.AddLog(new MigrateExecutionLog( + result.Succeded ? + MigrateExecutionLog.ExecutionState.Succeded : + MigrateExecutionLog.ExecutionState.Failed, + migration.Id, + migrationType, + result.MigratedDocuments)); + + await dbContext.SaveChangesAsync().ConfigureAwait(false); + } // Build indexes. foreach (var repository in dbContext.RepositoryRegister.ModelCollectionRepositoryMap.Values) diff --git a/src/MongODM.Core/Utility/DbContextMigrationManager.cs b/src/MongODM.Core/Utility/DbContextMigrationManager.cs index dd9afe1d..eedea143 100644 --- a/src/MongODM.Core/Utility/DbContextMigrationManager.cs +++ b/src/MongODM.Core/Utility/DbContextMigrationManager.cs @@ -1,5 +1,5 @@ using Etherna.MongODM.Extensions; -using Etherna.MongODM.Operations; +using Etherna.MongODM.Models.Internal; using Etherna.MongODM.Tasks; using MongoDB.Driver; using MongoDB.Driver.Linq; diff --git a/src/MongODM.Core/Utility/IDbContextMigrationManager.cs b/src/MongODM.Core/Utility/IDbContextMigrationManager.cs index a9298212..88b918ca 100644 --- a/src/MongODM.Core/Utility/IDbContextMigrationManager.cs +++ b/src/MongODM.Core/Utility/IDbContextMigrationManager.cs @@ -1,4 +1,4 @@ -using Etherna.MongODM.Operations; +using Etherna.MongODM.Models.Internal; using System.Collections.Generic; using System.Threading.Tasks; diff --git a/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs b/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs index 1b069a0d..ef0c059f 100644 --- a/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs +++ b/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs @@ -26,7 +26,7 @@ public HangfireTaskRunner( // Methods. public void RunMigrateDbContextTask(Type dbContextType, string migrateOpId) => backgroundJobClient.Enqueue( - task => task.RunAsync(dbContextType, migrateOpId)); + task => task.RunAsync(dbContextType, migrateOpId, null!)); public void RunUpdateDocDependenciesTask(Type dbContextType, Type modelType, Type keyType, IEnumerable idPaths, object modelId) => backgroundJobClient.Enqueue( diff --git a/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs b/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs index 4b304b0e..39282ff4 100644 --- a/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs +++ b/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs @@ -1,5 +1,6 @@ using Etherna.MongODM.Tasks; using Hangfire; +using Hangfire.Server; using System; using System.Reflection; using System.Threading.Tasks; @@ -19,13 +20,13 @@ public MigrateDbContextTaskFacade(IMigrateDbContextTask task) // Methods. [Queue(Queues.DB_MAINTENANCE)] - public Task RunAsync(Type dbContextType, string migrateOpId) + public Task RunAsync(Type dbContextType, string migrateOpId, PerformingContext context) { var method = typeof(MigrateDbContextTask).GetMethod( nameof(MigrateDbContextTask.RunAsync), BindingFlags.Public | BindingFlags.Instance) .MakeGenericMethod(dbContextType); - return (Task)method.Invoke(task, new object[] { migrateOpId }); + return (Task)method.Invoke(task, new object[] { migrateOpId, context.BackgroundJob.Id }); } } } From 6c45c90f857d742d17c5b473892a2f2d10ea4d49 Mon Sep 17 00:00:00 2001 From: Mirko Da Corte Date: Fri, 17 Jul 2020 00:31:38 +0200 Subject: [PATCH 4/5] Update background migration task implementation --- .../ServiceCollectionExtensions.cs | 8 +-- src/MongODM.Core/DbContext.cs | 19 ++++--- src/MongODM.Core/IDbContext.cs | 16 +++--- .../Migration/MongoCollectionMigration.cs | 30 ++++++++--- .../Migration/MongoDocumentMigration.cs | 21 +++++++- .../DbMigrationOpAgg/DocumentMigrationLog.cs | 23 ++++++++ .../DbMigrationOpAgg/IndexMigrationLog.cs | 18 +++++++ .../DbMigrationOpAgg/MigrationLogBase.cs | 28 ++++++++++ ...teOperation.cs => DbMigrationOperation.cs} | 16 +++--- .../MigrateOpAgg/MigrateExecutionLog.cs | 38 ------------- .../ModelMaps/DbMigrationOperationMap.cs | 23 ++++++++ .../ModelMaps/MigrateExecutionLogMap.cs | 14 ----- .../Models/Internal/ModelMaps/ModelBaseMap.cs | 26 +++++++++ .../Internal/ModelMaps/SeedOperationMap.cs | 13 +++++ .../Repositories/CollectionRepository.cs | 1 + .../Repositories/GridFSRepository.cs | 1 + src/MongODM.Core/Repositories/IRepository.cs | 1 + .../Repositories/RepositoryBase.cs | 1 + .../Serializers/ExtendedClassMapSerializer.cs | 4 +- .../Tasks/IMigrateDbContextTask.cs | 2 +- src/MongODM.Core/Tasks/ITaskRunner.cs | 2 +- .../Tasks/MigrateDbContextTask.cs | 54 +++++++++++-------- .../Utility/{DbContextCache.cs => DbCache.cs} | 4 +- ...ntextDependencies.cs => DbDependencies.cs} | 22 ++++---- ...DbContextMaintainer.cs => DbMaintainer.cs} | 4 +- ...rationManager.cs => DbMigrationManager.cs} | 22 ++++---- .../{IDbContextCache.cs => IDbCache.cs} | 4 +- ...textDependencies.cs => IDbDependencies.cs} | 8 +-- ...bContextMaintainer.cs => IDbMaintainer.cs} | 4 +- ...ationManager.cs => IDbMigrationManager.cs} | 8 +-- .../Tasks/HangfireTaskRunner.cs | 4 +- .../Tasks/MigrateDbContextTaskFacade.cs | 4 +- .../ExtendedClassMapSerializerTest.cs | 4 +- 33 files changed, 289 insertions(+), 158 deletions(-) create mode 100644 src/MongODM.Core/Models/Internal/DbMigrationOpAgg/DocumentMigrationLog.cs create mode 100644 src/MongODM.Core/Models/Internal/DbMigrationOpAgg/IndexMigrationLog.cs create mode 100644 src/MongODM.Core/Models/Internal/DbMigrationOpAgg/MigrationLogBase.cs rename src/MongODM.Core/Models/Internal/{MigrateOperation.cs => DbMigrationOperation.cs} (79%) delete mode 100644 src/MongODM.Core/Models/Internal/MigrateOpAgg/MigrateExecutionLog.cs create mode 100644 src/MongODM.Core/Models/Internal/ModelMaps/DbMigrationOperationMap.cs delete mode 100644 src/MongODM.Core/Models/Internal/ModelMaps/MigrateExecutionLogMap.cs create mode 100644 src/MongODM.Core/Models/Internal/ModelMaps/ModelBaseMap.cs create mode 100644 src/MongODM.Core/Models/Internal/ModelMaps/SeedOperationMap.cs rename src/MongODM.Core/Utility/{DbContextCache.cs => DbCache.cs} (95%) rename src/MongODM.Core/Utility/{DbContextDependencies.cs => DbDependencies.cs} (68%) rename src/MongODM.Core/Utility/{DbContextMaintainer.cs => DbMaintainer.cs} (94%) rename src/MongODM.Core/Utility/{DbContextMigrationManager.cs => DbMigrationManager.cs} (70%) rename src/MongODM.Core/Utility/{IDbContextCache.cs => IDbCache.cs} (90%) rename src/MongODM.Core/Utility/{IDbContextDependencies.cs => IDbDependencies.cs} (67%) rename src/MongODM.Core/Utility/{IDbContextMaintainer.cs => IDbMaintainer.cs} (78%) rename src/MongODM.Core/Utility/{IDbContextMigrationManager.cs => IDbMigrationManager.cs} (59%) diff --git a/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs b/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs index f0961743..eb7a05fa 100644 --- a/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs +++ b/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs @@ -60,10 +60,10 @@ public static MongODMConfiguration UseMongODM(); - services.TryAddTransient(); - services.TryAddTransient(); - services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); + services.TryAddTransient(); services.TryAddTransient(); services.TryAddTransient(); services.TryAddSingleton(); diff --git a/src/MongODM.Core/DbContext.cs b/src/MongODM.Core/DbContext.cs index 94bbcd43..8e484864 100644 --- a/src/MongODM.Core/DbContext.cs +++ b/src/MongODM.Core/DbContext.cs @@ -25,7 +25,7 @@ public abstract class DbContext : IDbContext // Constructors and initialization. public DbContext( - IDbContextDependencies dependencies, + IDbDependencies dependencies, DbContextOptions options) { if (dependencies is null) @@ -34,9 +34,9 @@ public DbContext( throw new ArgumentNullException(nameof(options)); ApplicationVersion = options.ApplicationVersion; - DbCache = dependencies.DbContextCache; - DbMaintainer = dependencies.DbContextMaintainer; - DbContextMigrationManager = dependencies.DbContextMigrationManager; + DbCache = dependencies.DbCache; + DbMaintainer = dependencies.DbMaintainer; + DbMigrationManager = dependencies.DbMigrationManager; DbOperations = new CollectionRepository(options.DbOperationsCollectionName); DocumentSchemaRegister = dependencies.DocumentSchemaRegister; Identifier = options.Identifier ?? GetType().Name; @@ -65,7 +65,10 @@ public DbContext( // Register model maps. //internal maps + new DbMigrationOperationMap().Register(this); + new ModelBaseMap().Register(this); new OperationBaseMap().Register(this); + new SeedOperationMap().Register(this); //application maps foreach (var maps in ModelMapsCollectors) @@ -86,14 +89,14 @@ public DbContext( .ToList(); public IMongoClient Client { get; } public IMongoDatabase Database { get; } - public IDbContextCache DbCache { get; } - public IDbContextMaintainer DbMaintainer { get; } - public IDbContextMigrationManager DbContextMigrationManager { get; } + public IDbCache DbCache { get; } + public IDbMaintainer DbMaintainer { get; } + public IDbMigrationManager DbMigrationManager { get; } public ICollectionRepository DbOperations { get; } + public virtual IEnumerable DocumentMigrationList { get; } = Array.Empty(); public IDocumentSchemaRegister DocumentSchemaRegister { get; } public string Identifier { get; } public SemanticVersion LibraryVersion { get; } - public virtual IEnumerable MigrationTaskList { get; } = Array.Empty(); public IProxyGenerator ProxyGenerator { get; } public IRepositoryRegister RepositoryRegister { get; } public ISerializerModifierAccessor SerializerModifierAccessor { get; } diff --git a/src/MongODM.Core/IDbContext.cs b/src/MongODM.Core/IDbContext.cs index 7e004769..5cbe8ab6 100644 --- a/src/MongODM.Core/IDbContext.cs +++ b/src/MongODM.Core/IDbContext.cs @@ -36,23 +36,28 @@ public interface IDbContext /// /// Database cache container. /// - IDbContextCache DbCache { get; } + IDbCache DbCache { get; } /// /// Database operator interested into maintenance tasks. /// - IDbContextMaintainer DbMaintainer { get; } + IDbMaintainer DbMaintainer { get; } /// /// Manage migrations over database context /// - IDbContextMigrationManager DbContextMigrationManager { get; } + IDbMigrationManager DbMigrationManager { get; } /// /// Internal collection for keep db operations execution log /// ICollectionRepository DbOperations { get; } + /// + /// List of registered migration tasks + /// + IEnumerable DocumentMigrationList { get; } + /// /// Container for model serialization and document schema information. /// @@ -68,11 +73,6 @@ public interface IDbContext /// SemanticVersion LibraryVersion { get; } - /// - /// List of registered migration tasks - /// - IEnumerable MigrationTaskList { get; } - /// /// Current model proxy generator. /// diff --git a/src/MongODM.Core/Migration/MongoCollectionMigration.cs b/src/MongODM.Core/Migration/MongoCollectionMigration.cs index f2033432..9b2237d1 100644 --- a/src/MongODM.Core/Migration/MongoCollectionMigration.cs +++ b/src/MongODM.Core/Migration/MongoCollectionMigration.cs @@ -45,15 +45,31 @@ public MongoCollectionMigration( } // Methods. - public override Task MigrateAsync( + public override async Task MigrateAsync( int callbackEveryDocuments = 0, Func? callbackAsync = null, - CancellationToken cancellationToken = default) => - sourceCollection.Find(Builders.Filter.Empty, new FindOptions { NoCursorTimeout = true }) - .ForEachAsync(obj => + CancellationToken cancellationToken = default) + { + if (callbackEveryDocuments < 0) + throw new ArgumentOutOfRangeException(nameof(callbackEveryDocuments), "Value can't be negative"); + + // Migrate documents. + var totMigratedDocuments = 0L; + await sourceCollection.Find(Builders.Filter.Empty, new FindOptions { NoCursorTimeout = true }) + .ForEachAsync(async model => { - if (discriminator(obj)) - destinationCollection.InsertOneAsync(converter(obj)); - }, cancellationToken); + if (callbackEveryDocuments > 0 && + totMigratedDocuments % callbackEveryDocuments == 0 && + callbackAsync != null) + await callbackAsync.Invoke(totMigratedDocuments).ConfigureAwait(false); + + if (discriminator(model)) + await destinationCollection.InsertOneAsync(converter(model)).ConfigureAwait(false); + + totMigratedDocuments++; + }, cancellationToken).ConfigureAwait(false); + + return MigrationResult.Succeeded(totMigratedDocuments); + } } } diff --git a/src/MongODM.Core/Migration/MongoDocumentMigration.cs b/src/MongODM.Core/Migration/MongoDocumentMigration.cs index 3a3ea97f..59a758e1 100644 --- a/src/MongODM.Core/Migration/MongoDocumentMigration.cs +++ b/src/MongODM.Core/Migration/MongoDocumentMigration.cs @@ -41,6 +41,10 @@ public override async Task MigrateAsync( Func? callbackAsync = null, CancellationToken cancellationToken = default) { + if (callbackEveryDocuments < 0) + throw new ArgumentOutOfRangeException(nameof(callbackEveryDocuments), "Value can't be negative"); + + // Building filter. var filterBuilder = Builders.Filter; var filter = filterBuilder.Or( // No version in document (very old). @@ -65,9 +69,22 @@ public override async Task MigrateAsync( filterBuilder.Eq($"{DbContext.DocumentVersionElementName}.1", minimumDocumentVersion.MinorRelease), filterBuilder.Lt($"{DbContext.DocumentVersionElementName}.2", minimumDocumentVersion.PatchRelease))); - // Replace documents. + // Migrate documents. + var totMigratedDocuments = 0L; await sourceCollection.Find(filter, new FindOptions { NoCursorTimeout = true }) - .ForEachAsync(obj => sourceCollection.ReplaceOneAsync(Builders.Filter.Eq(m => m.Id, obj.Id), obj), cancellationToken).ConfigureAwait(false); + .ForEachAsync(async model => + { + if (callbackEveryDocuments > 0 && + totMigratedDocuments % callbackEveryDocuments == 0 && + callbackAsync != null) + await callbackAsync.Invoke(totMigratedDocuments).ConfigureAwait(false); + + await sourceCollection.ReplaceOneAsync(Builders.Filter.Eq(m => m.Id, model.Id), model).ConfigureAwait(false); + + totMigratedDocuments++; + }, cancellationToken).ConfigureAwait(false); + + return MigrationResult.Succeeded(totMigratedDocuments); } } } diff --git a/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/DocumentMigrationLog.cs b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/DocumentMigrationLog.cs new file mode 100644 index 00000000..49477d93 --- /dev/null +++ b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/DocumentMigrationLog.cs @@ -0,0 +1,23 @@ +using System; + +namespace Etherna.MongODM.Models.Internal.DbMigrationOpAgg +{ + public class DocumentMigrationLog : MigrationLogBase + { + // Constructors. + public DocumentMigrationLog( + string documentMigrationId, + ExecutionState state, + long totMigratedDocs) + : base(state) + { + DocumentMigrationId = documentMigrationId; + TotMigratedDocs = totMigratedDocs; + } + protected DocumentMigrationLog() { } + + // Properties. + public virtual string DocumentMigrationId { get; protected set; } = default!; + public virtual long TotMigratedDocs { get; protected set; } + } +} diff --git a/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/IndexMigrationLog.cs b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/IndexMigrationLog.cs new file mode 100644 index 00000000..c75d408d --- /dev/null +++ b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/IndexMigrationLog.cs @@ -0,0 +1,18 @@ +namespace Etherna.MongODM.Models.Internal.DbMigrationOpAgg +{ + class IndexMigrationLog : MigrationLogBase + { + // Constructors. + public IndexMigrationLog( + string repository, + ExecutionState state) + : base(state) + { + Repository = repository; + } + protected IndexMigrationLog() { } + + // Properties. + public virtual string Repository { get; protected set; } = default!; + } +} diff --git a/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/MigrationLogBase.cs b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/MigrationLogBase.cs new file mode 100644 index 00000000..71126870 --- /dev/null +++ b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/MigrationLogBase.cs @@ -0,0 +1,28 @@ +using System; + +namespace Etherna.MongODM.Models.Internal.DbMigrationOpAgg +{ + public abstract class MigrationLogBase : ModelBase + { + // Enums. + public enum ExecutionState + { + Executing, + Succeded, + Skipped, + Failed + } + + // Constructors. + public MigrationLogBase(ExecutionState state) + { + CreationDateTime = DateTime.Now; + State = state; + } + protected MigrationLogBase() { } + + // Properties. + public virtual ExecutionState State { get; protected set; } + public virtual DateTime CreationDateTime { get; protected set; } + } +} diff --git a/src/MongODM.Core/Models/Internal/MigrateOperation.cs b/src/MongODM.Core/Models/Internal/DbMigrationOperation.cs similarity index 79% rename from src/MongODM.Core/Models/Internal/MigrateOperation.cs rename to src/MongODM.Core/Models/Internal/DbMigrationOperation.cs index 9486b579..73e15cdb 100644 --- a/src/MongODM.Core/Models/Internal/MigrateOperation.cs +++ b/src/MongODM.Core/Models/Internal/DbMigrationOperation.cs @@ -1,11 +1,11 @@ using Etherna.MongODM.Attributes; -using Etherna.MongODM.Models.Internal.MigrateOpAgg; +using Etherna.MongODM.Models.Internal.DbMigrationOpAgg; using System; using System.Collections.Generic; namespace Etherna.MongODM.Models.Internal { - public class MigrateOperation : OperationBase + public class DbMigrationOperation : OperationBase { // Enums. public enum Status @@ -17,31 +17,31 @@ public enum Status } // Fields. - private List _logs = new List(); + private List _logs = new List(); // Constructors. - public MigrateOperation(IDbContext dbContext, string? author) + public DbMigrationOperation(IDbContext dbContext, string? author) : base(dbContext) { Author = author; CurrentStatus = Status.New; } - protected MigrateOperation() { } + protected DbMigrationOperation() { } // Properties. public virtual string? Author { get; protected set; } public virtual DateTime CompletedDateTime { get; protected set; } public virtual Status CurrentStatus { get; protected set; } - public virtual IEnumerable Logs + public virtual IEnumerable Logs { get => _logs; - protected set => _logs = new List(value ?? Array.Empty()); + protected set => _logs = new List(value ?? Array.Empty()); } public virtual string? TaskId { get; protected set; } // Methods. [PropertyAlterer(nameof(Logs))] - public virtual void AddLog(MigrateExecutionLog log) + public virtual void AddLog(MigrationLogBase log) { if (log is null) throw new ArgumentNullException(nameof(log)); diff --git a/src/MongODM.Core/Models/Internal/MigrateOpAgg/MigrateExecutionLog.cs b/src/MongODM.Core/Models/Internal/MigrateOpAgg/MigrateExecutionLog.cs deleted file mode 100644 index 6887532b..00000000 --- a/src/MongODM.Core/Models/Internal/MigrateOpAgg/MigrateExecutionLog.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; - -namespace Etherna.MongODM.Models.Internal.MigrateOpAgg -{ - public class MigrateExecutionLog : ModelBase - { - // Enums. - public enum ExecutionState - { - Executing, - Succeded, - Skipped, - Failed - } - - // Constructors. - public MigrateExecutionLog( - ExecutionState action, - string migrationId, - string migrationType, - long totMigratedDocs) - { - Action = action; - CreationDateTime = DateTime.Now; - MigrationId = migrationId; - MigrationType = migrationType; - TotMigratedDocs = totMigratedDocs; - } - protected MigrateExecutionLog() { } - - // Properties. - public virtual ExecutionState Action { get; protected set; } - public virtual DateTime CreationDateTime { get; protected set; } - public virtual string MigrationId { get; protected set; } = default!; - public string MigrationType { get; } = default!; - public long TotMigratedDocs { get; protected set; } - } -} diff --git a/src/MongODM.Core/Models/Internal/ModelMaps/DbMigrationOperationMap.cs b/src/MongODM.Core/Models/Internal/ModelMaps/DbMigrationOperationMap.cs new file mode 100644 index 00000000..2977955e --- /dev/null +++ b/src/MongODM.Core/Models/Internal/ModelMaps/DbMigrationOperationMap.cs @@ -0,0 +1,23 @@ +using Etherna.MongODM.Models.Internal.DbMigrationOpAgg; +using Etherna.MongODM.Serialization; + +namespace Etherna.MongODM.Models.Internal.ModelMaps +{ + class DbMigrationOperationMap : IModelMapsCollector + { + public void Register(IDbContext dbContext) + { + dbContext.DocumentSchemaRegister.RegisterModelSchema( + "0.20.0"); + + dbContext.DocumentSchemaRegister.RegisterModelSchema( + "0.20.0"); + + dbContext.DocumentSchemaRegister.RegisterModelSchema( + "0.20.0"); + + dbContext.DocumentSchemaRegister.RegisterModelSchema( + "0.20.0"); + } + } +} diff --git a/src/MongODM.Core/Models/Internal/ModelMaps/MigrateExecutionLogMap.cs b/src/MongODM.Core/Models/Internal/ModelMaps/MigrateExecutionLogMap.cs deleted file mode 100644 index d6a4795a..00000000 --- a/src/MongODM.Core/Models/Internal/ModelMaps/MigrateExecutionLogMap.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Etherna.MongODM.Models.Internal.MigrateOpAgg; -using Etherna.MongODM.Serialization; - -namespace Etherna.MongODM.Models.Internal.ModelMaps -{ - class MigrateExecutionLogMap : IModelMapsCollector - { - public void Register(IDbContext dbContext) - { - dbContext.DocumentSchemaRegister.RegisterModelSchema( - "0.20.0"); //mongodm library's version - } - } -} diff --git a/src/MongODM.Core/Models/Internal/ModelMaps/ModelBaseMap.cs b/src/MongODM.Core/Models/Internal/ModelMaps/ModelBaseMap.cs new file mode 100644 index 00000000..f7dd9ebe --- /dev/null +++ b/src/MongODM.Core/Models/Internal/ModelMaps/ModelBaseMap.cs @@ -0,0 +1,26 @@ +using Etherna.MongODM.Serialization; +using MongoDB.Bson; +using MongoDB.Bson.Serialization.IdGenerators; +using MongoDB.Bson.Serialization.Serializers; + +namespace Etherna.MongODM.Models.Internal.ModelMaps +{ + class ModelBaseMap : IModelMapsCollector + { + public void Register(IDbContext dbContext) + { + // register class maps. + dbContext.DocumentSchemaRegister.RegisterModelSchema("0.20.0"); + + dbContext.DocumentSchemaRegister.RegisterModelSchema>("0.20.0", + cm => + { + cm.AutoMap(); + + // Set Id representation. + cm.IdMemberMap.SetSerializer(new StringSerializer(BsonType.ObjectId)) + .SetIdGenerator(new StringObjectIdGenerator()); + }); + } + } +} diff --git a/src/MongODM.Core/Models/Internal/ModelMaps/SeedOperationMap.cs b/src/MongODM.Core/Models/Internal/ModelMaps/SeedOperationMap.cs new file mode 100644 index 00000000..5a918790 --- /dev/null +++ b/src/MongODM.Core/Models/Internal/ModelMaps/SeedOperationMap.cs @@ -0,0 +1,13 @@ +using Etherna.MongODM.Serialization; + +namespace Etherna.MongODM.Models.Internal.ModelMaps +{ + class SeedOperationMap : IModelMapsCollector + { + public void Register(IDbContext dbContext) + { + dbContext.DocumentSchemaRegister.RegisterModelSchema( + "0.20.0"); + } + } +} diff --git a/src/MongODM.Core/Repositories/CollectionRepository.cs b/src/MongODM.Core/Repositories/CollectionRepository.cs index 643e50ff..cd7b0273 100644 --- a/src/MongODM.Core/Repositories/CollectionRepository.cs +++ b/src/MongODM.Core/Repositories/CollectionRepository.cs @@ -35,6 +35,7 @@ public CollectionRepository(CollectionRepositoryOptions options) // Properties. public IMongoCollection Collection => _collection ??= DbContext.Database.GetCollection(options.Name); + public override string Name => options.Name; // Public methods. public override async Task BuildIndexesAsync(IDocumentSchemaRegister schemaRegister, CancellationToken cancellationToken = default) diff --git a/src/MongODM.Core/Repositories/GridFSRepository.cs b/src/MongODM.Core/Repositories/GridFSRepository.cs index 4d7215e3..cfd371da 100644 --- a/src/MongODM.Core/Repositories/GridFSRepository.cs +++ b/src/MongODM.Core/Repositories/GridFSRepository.cs @@ -34,6 +34,7 @@ public GridFSRepository(GridFSRepositoryOptions options) // Properties. public IGridFSBucket GridFSBucket => _gridFSBucket ??= new GridFSBucket(DbContext.Database, new GridFSBucketOptions { BucketName = options.Name }); + public override string Name => options.Name; // Methods. public override Task BuildIndexesAsync(IDocumentSchemaRegister schemaRegister, CancellationToken cancellationToken = default) => Task.CompletedTask; diff --git a/src/MongODM.Core/Repositories/IRepository.cs b/src/MongODM.Core/Repositories/IRepository.cs index 636faffe..acfb301a 100644 --- a/src/MongODM.Core/Repositories/IRepository.cs +++ b/src/MongODM.Core/Repositories/IRepository.cs @@ -12,6 +12,7 @@ public interface IRepository : IDbContextInitializable IDbContext DbContext { get; } Type GetKeyType { get; } Type GetModelType { get; } + string Name { get; } Task BuildIndexesAsync( IDocumentSchemaRegister schemaRegister, diff --git a/src/MongODM.Core/Repositories/RepositoryBase.cs b/src/MongODM.Core/Repositories/RepositoryBase.cs index 22237fc1..1f8b7ba4 100644 --- a/src/MongODM.Core/Repositories/RepositoryBase.cs +++ b/src/MongODM.Core/Repositories/RepositoryBase.cs @@ -31,6 +31,7 @@ public virtual void Initialize(IDbContext dbContext) public Type GetKeyType => typeof(TKey); public Type GetModelType => typeof(TModel); public bool IsInitialized { get; private set; } + public abstract string Name { get; } // Methods. public abstract Task BuildIndexesAsync(IDocumentSchemaRegister schemaRegister, CancellationToken cancellationToken = default); diff --git a/src/MongODM.Core/Serialization/Serializers/ExtendedClassMapSerializer.cs b/src/MongODM.Core/Serialization/Serializers/ExtendedClassMapSerializer.cs index cd201b0e..a4bc991d 100644 --- a/src/MongODM.Core/Serialization/Serializers/ExtendedClassMapSerializer.cs +++ b/src/MongODM.Core/Serialization/Serializers/ExtendedClassMapSerializer.cs @@ -28,7 +28,7 @@ private struct ExtraElementCondition private readonly BsonElement documentVersionElement; // Fields. - private readonly IDbContextCache dbCache; + private readonly IDbCache dbCache; private readonly ISerializerModifierAccessor serializerModifierAccessor; private readonly ICollection extraElements; private readonly Func> fixDeserializedModelAsync; @@ -36,7 +36,7 @@ private struct ExtraElementCondition // Constructor. public ExtendedClassMapSerializer( - IDbContextCache dbCache, + IDbCache dbCache, SemanticVersion documentVersion, ISerializerModifierAccessor serializerModifierAccessor, Func>? fixDeserializedModelAsync = null) diff --git a/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs b/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs index c1068187..23c2e226 100644 --- a/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs +++ b/src/MongODM.Core/Tasks/IMigrateDbContextTask.cs @@ -4,7 +4,7 @@ namespace Etherna.MongODM.Tasks { public interface IMigrateDbContextTask { - Task RunAsync(string authorId, string taskId) + Task RunAsync(string dbMigrationOpId, string taskId) where TDbContext : class, IDbContext; } } \ No newline at end of file diff --git a/src/MongODM.Core/Tasks/ITaskRunner.cs b/src/MongODM.Core/Tasks/ITaskRunner.cs index 32415ea5..1a0e241f 100644 --- a/src/MongODM.Core/Tasks/ITaskRunner.cs +++ b/src/MongODM.Core/Tasks/ITaskRunner.cs @@ -5,7 +5,7 @@ namespace Etherna.MongODM.Tasks { public interface ITaskRunner { - void RunMigrateDbContextTask(Type dbContextType, string migrateOpId); + void RunMigrateDbTask(Type dbContextType, string dbMigrationOpId); void RunUpdateDocDependenciesTask(Type dbContextType, Type modelType, Type keyType, IEnumerable idPaths, object modelId); } } diff --git a/src/MongODM.Core/Tasks/MigrateDbContextTask.cs b/src/MongODM.Core/Tasks/MigrateDbContextTask.cs index 337deb6c..65a64b3c 100644 --- a/src/MongODM.Core/Tasks/MigrateDbContextTask.cs +++ b/src/MongODM.Core/Tasks/MigrateDbContextTask.cs @@ -1,5 +1,5 @@ using Etherna.MongODM.Models.Internal; -using Etherna.MongODM.Models.Internal.MigrateOpAgg; +using Etherna.MongODM.Models.Internal.DbMigrationOpAgg; using System; using System.Threading.Tasks; @@ -18,41 +18,37 @@ public MigrateDbContextTask( } // Methods. - public async Task RunAsync(string migrateOpId, string taskId) + public async Task RunAsync(string dbMigrationOpId, string taskId) where TDbContext : class, IDbContext { var dbContext = (TDbContext)serviceProvider.GetService(typeof(TDbContext)); - var migrateOp = (MigrateOperation)await dbContext.DbOperations.FindOneAsync(migrateOpId).ConfigureAwait(false); + var dbMigrationOp = (DbMigrationOperation)await dbContext.DbOperations.FindOneAsync(dbMigrationOpId).ConfigureAwait(false); // Start migrate operation. - migrateOp.TaskStarted(taskId); + dbMigrationOp.TaskStarted(taskId); await dbContext.SaveChangesAsync().ConfigureAwait(false); - // Migrate collections. - foreach (var migration in dbContext.MigrationTaskList) + // Migrate documents. + foreach (var docMigration in dbContext.DocumentMigrationList) { - var migrationType = migration.GetType().Name; - - //running migration - var result = await migration.MigrateAsync(500, + //running document migration + var result = await docMigration.MigrateAsync(500, async procDocs => { - migrateOp.AddLog(new MigrateExecutionLog( - MigrateExecutionLog.ExecutionState.Executing, - migration.Id, - migrationType, + dbMigrationOp.AddLog(new DocumentMigrationLog( + docMigration.Id, + MigrationLogBase.ExecutionState.Executing, procDocs)); await dbContext.SaveChangesAsync().ConfigureAwait(false); }).ConfigureAwait(false); - //ended migration log - migrateOp.AddLog(new MigrateExecutionLog( + //ended document migration log + dbMigrationOp.AddLog(new DocumentMigrationLog( + docMigration.Id, result.Succeded ? - MigrateExecutionLog.ExecutionState.Succeded : - MigrateExecutionLog.ExecutionState.Failed, - migration.Id, - migrationType, + MigrationLogBase.ExecutionState.Succeded : + MigrationLogBase.ExecutionState.Failed, result.MigratedDocuments)); await dbContext.SaveChangesAsync().ConfigureAwait(false); @@ -60,7 +56,23 @@ public async Task RunAsync(string migrateOpId, string taskId) // Build indexes. foreach (var repository in dbContext.RepositoryRegister.ModelCollectionRepositoryMap.Values) - await repository.BuildIndexesAsync(dbContext.DocumentSchemaRegister, cancellationToken).ConfigureAwait(false); + { + dbMigrationOp.AddLog(new IndexMigrationLog( + repository.Name, + MigrationLogBase.ExecutionState.Executing)); + await dbContext.SaveChangesAsync().ConfigureAwait(false); + + await repository.BuildIndexesAsync(dbContext.DocumentSchemaRegister).ConfigureAwait(false); + + dbMigrationOp.AddLog(new IndexMigrationLog( + repository.Name, + MigrationLogBase.ExecutionState.Succeded)); + await dbContext.SaveChangesAsync().ConfigureAwait(false); + } + + // Complete task. + dbMigrationOp.TaskCompleted(); + await dbContext.SaveChangesAsync().ConfigureAwait(false); } } } diff --git a/src/MongODM.Core/Utility/DbContextCache.cs b/src/MongODM.Core/Utility/DbCache.cs similarity index 95% rename from src/MongODM.Core/Utility/DbContextCache.cs rename to src/MongODM.Core/Utility/DbCache.cs index 20c7065b..6eaa5b7d 100644 --- a/src/MongODM.Core/Utility/DbContextCache.cs +++ b/src/MongODM.Core/Utility/DbCache.cs @@ -5,7 +5,7 @@ namespace Etherna.MongODM.Utility { - public class DbContextCache : IDbContextCache + public class DbCache : IDbCache { // Consts. private const string CacheKey = "DBCache"; @@ -14,7 +14,7 @@ public class DbContextCache : IDbContextCache private readonly IExecutionContext executionContext; // Constructors. - public DbContextCache(IExecutionContext executionContext) + public DbCache(IExecutionContext executionContext) { this.executionContext = executionContext ?? throw new ArgumentNullException(nameof(executionContext)); } diff --git a/src/MongODM.Core/Utility/DbContextDependencies.cs b/src/MongODM.Core/Utility/DbDependencies.cs similarity index 68% rename from src/MongODM.Core/Utility/DbContextDependencies.cs rename to src/MongODM.Core/Utility/DbDependencies.cs index c108da6d..be2096c3 100644 --- a/src/MongODM.Core/Utility/DbContextDependencies.cs +++ b/src/MongODM.Core/Utility/DbDependencies.cs @@ -5,12 +5,12 @@ namespace Etherna.MongODM.Utility { - public class DbContextDependencies : IDbContextDependencies + public class DbDependencies : IDbDependencies { - public DbContextDependencies( - IDbContextCache dbCache, - IDbContextMaintainer dbMaintainer, - IDbContextMigrationManager dbContextMigrationManager, + public DbDependencies( + IDbCache dbCache, + IDbMaintainer dbMaintainer, + IDbMigrationManager dbContextMigrationManager, IDocumentSchemaRegister documentSchemaRegister, IProxyGenerator proxyGenerator, IRepositoryRegister repositoryRegister, @@ -21,18 +21,18 @@ public DbContextDependencies( #pragma warning restore CA1801 // Review unused parameters #pragma warning restore IDE0060 // Remove unused parameter { - DbContextCache = dbCache; - DbContextMaintainer = dbMaintainer; - DbContextMigrationManager = dbContextMigrationManager; + DbCache = dbCache; + DbMaintainer = dbMaintainer; + DbMigrationManager = dbContextMigrationManager; DocumentSchemaRegister = documentSchemaRegister; ProxyGenerator = proxyGenerator; RepositoryRegister = repositoryRegister; SerializerModifierAccessor = serializerModifierAccessor; } - public IDbContextCache DbContextCache { get; } - public IDbContextMaintainer DbContextMaintainer { get; } - public IDbContextMigrationManager DbContextMigrationManager { get; } + public IDbCache DbCache { get; } + public IDbMaintainer DbMaintainer { get; } + public IDbMigrationManager DbMigrationManager { get; } public IDocumentSchemaRegister DocumentSchemaRegister { get; } public IProxyGenerator ProxyGenerator { get; } public IRepositoryRegister RepositoryRegister { get; } diff --git a/src/MongODM.Core/Utility/DbContextMaintainer.cs b/src/MongODM.Core/Utility/DbMaintainer.cs similarity index 94% rename from src/MongODM.Core/Utility/DbContextMaintainer.cs rename to src/MongODM.Core/Utility/DbMaintainer.cs index 9e838a08..e871015a 100644 --- a/src/MongODM.Core/Utility/DbContextMaintainer.cs +++ b/src/MongODM.Core/Utility/DbMaintainer.cs @@ -6,14 +6,14 @@ namespace Etherna.MongODM.Utility { - public class DbContextMaintainer : IDbContextMaintainer + public class DbMaintainer : IDbMaintainer { // Fields. private IDbContext dbContext = default!; private readonly ITaskRunner taskRunner; // Constructors and initialization. - public DbContextMaintainer(ITaskRunner taskRunner) + public DbMaintainer(ITaskRunner taskRunner) { this.taskRunner = taskRunner; } diff --git a/src/MongODM.Core/Utility/DbContextMigrationManager.cs b/src/MongODM.Core/Utility/DbMigrationManager.cs similarity index 70% rename from src/MongODM.Core/Utility/DbContextMigrationManager.cs rename to src/MongODM.Core/Utility/DbMigrationManager.cs index eedea143..16823581 100644 --- a/src/MongODM.Core/Utility/DbContextMigrationManager.cs +++ b/src/MongODM.Core/Utility/DbMigrationManager.cs @@ -9,14 +9,14 @@ namespace Etherna.MongODM.Utility { - public class DbContextMigrationManager : IDbContextMigrationManager, IDbContextInitializable + public class DbMigrationManager : IDbMigrationManager, IDbContextInitializable { // Fields. private IDbContext dbContext = default!; private readonly ITaskRunner taskRunner; // Constructor and initialization. - public DbContextMigrationManager(ITaskRunner taskRunner) + public DbMigrationManager(ITaskRunner taskRunner) { this.taskRunner = taskRunner; } @@ -34,31 +34,31 @@ public void Initialize(IDbContext dbContext) public bool IsInitialized { get; private set; } // Methods. - public async Task> GetLastMigrationsAsync(int page, int take) => + public async Task> GetLastMigrationsAsync(int page, int take) => await dbContext.DbOperations.QueryElementsAsync(elements => - elements.OfType() + elements.OfType() .PaginateDescending(r => r.CreationDateTime, page, take) .ToListAsync()).ConfigureAwait(false); - public async Task GetMigrationAsync(string migrateOperationId) + public async Task GetMigrationAsync(string migrateOperationId) { if (migrateOperationId is null) throw new ArgumentNullException(nameof(migrateOperationId)); var migrateOp = await dbContext.DbOperations.QueryElementsAsync(elements => - elements.OfType() + elements.OfType() .Where(op => op.Id == migrateOperationId) .FirstAsync()).ConfigureAwait(false); return migrateOp; } - public async Task IsMigrationRunningAsync() + public async Task IsMigrationRunningAsync() { var migrateOp = await dbContext.DbOperations.QueryElementsAsync(elements => - elements.OfType() + elements.OfType() .Where(op => op.DbContextName == dbContext.Identifier) - .Where(op => op.CurrentStatus == MigrateOperation.Status.Running) + .Where(op => op.CurrentStatus == DbMigrationOperation.Status.Running) .FirstOrDefaultAsync()).ConfigureAwait(false); return migrateOp; @@ -66,10 +66,10 @@ public async Task GetMigrationAsync(string migrateOperationId) public async Task StartDbContextMigrationAsync(string authorId) { - var migrateOp = new MigrateOperation(dbContext, authorId); + var migrateOp = new DbMigrationOperation(dbContext, authorId); await dbContext.DbOperations.CreateAsync(migrateOp).ConfigureAwait(false); - taskRunner.RunMigrateDbContextTask(dbContext.GetType(), migrateOp.Id); + taskRunner.RunMigrateDbTask(dbContext.GetType(), migrateOp.Id); } } } diff --git a/src/MongODM.Core/Utility/IDbContextCache.cs b/src/MongODM.Core/Utility/IDbCache.cs similarity index 90% rename from src/MongODM.Core/Utility/IDbContextCache.cs rename to src/MongODM.Core/Utility/IDbCache.cs index a1832174..7979c869 100644 --- a/src/MongODM.Core/Utility/IDbContextCache.cs +++ b/src/MongODM.Core/Utility/IDbCache.cs @@ -4,9 +4,9 @@ namespace Etherna.MongODM.Utility { /// - /// Interface for implementation. + /// Interface for implementation. /// - public interface IDbContextCache + public interface IDbCache { // Properties. /// diff --git a/src/MongODM.Core/Utility/IDbContextDependencies.cs b/src/MongODM.Core/Utility/IDbDependencies.cs similarity index 67% rename from src/MongODM.Core/Utility/IDbContextDependencies.cs rename to src/MongODM.Core/Utility/IDbDependencies.cs index f362e8ad..ed4515ff 100644 --- a/src/MongODM.Core/Utility/IDbContextDependencies.cs +++ b/src/MongODM.Core/Utility/IDbDependencies.cs @@ -5,11 +5,11 @@ namespace Etherna.MongODM.Utility { - public interface IDbContextDependencies + public interface IDbDependencies { - IDbContextCache DbContextCache { get; } - IDbContextMaintainer DbContextMaintainer { get; } - IDbContextMigrationManager DbContextMigrationManager { get; } + IDbCache DbCache { get; } + IDbMaintainer DbMaintainer { get; } + IDbMigrationManager DbMigrationManager { get; } IDocumentSchemaRegister DocumentSchemaRegister { get; } IProxyGenerator ProxyGenerator { get; } IRepositoryRegister RepositoryRegister { get; } diff --git a/src/MongODM.Core/Utility/IDbContextMaintainer.cs b/src/MongODM.Core/Utility/IDbMaintainer.cs similarity index 78% rename from src/MongODM.Core/Utility/IDbContextMaintainer.cs rename to src/MongODM.Core/Utility/IDbMaintainer.cs index 770e6449..db9c9da3 100644 --- a/src/MongODM.Core/Utility/IDbContextMaintainer.cs +++ b/src/MongODM.Core/Utility/IDbMaintainer.cs @@ -3,9 +3,9 @@ namespace Etherna.MongODM.Utility { /// - /// Interface for implementation. + /// Interface for implementation. /// - public interface IDbContextMaintainer : IDbContextInitializable + public interface IDbMaintainer : IDbContextInitializable { // Methods. /// diff --git a/src/MongODM.Core/Utility/IDbContextMigrationManager.cs b/src/MongODM.Core/Utility/IDbMigrationManager.cs similarity index 59% rename from src/MongODM.Core/Utility/IDbContextMigrationManager.cs rename to src/MongODM.Core/Utility/IDbMigrationManager.cs index 88b918ca..ef0ae156 100644 --- a/src/MongODM.Core/Utility/IDbContextMigrationManager.cs +++ b/src/MongODM.Core/Utility/IDbMigrationManager.cs @@ -4,13 +4,13 @@ namespace Etherna.MongODM.Utility { - public interface IDbContextMigrationManager + public interface IDbMigrationManager { - Task IsMigrationRunningAsync(); + Task IsMigrationRunningAsync(); - Task> GetLastMigrationsAsync(int page, int take); + Task> GetLastMigrationsAsync(int page, int take); - Task GetMigrationAsync(string migrateOperationId); + Task GetMigrationAsync(string migrateOperationId); /// /// Start a db context migration process. diff --git a/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs b/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs index ef0c059f..28310ef3 100644 --- a/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs +++ b/src/MongODM.Hangfire/Tasks/HangfireTaskRunner.cs @@ -24,9 +24,9 @@ public HangfireTaskRunner( } // Methods. - public void RunMigrateDbContextTask(Type dbContextType, string migrateOpId) => + public void RunMigrateDbTask(Type dbContextType, string dbMigrationOpId) => backgroundJobClient.Enqueue( - task => task.RunAsync(dbContextType, migrateOpId, null!)); + task => task.RunAsync(dbContextType, dbMigrationOpId, null!)); public void RunUpdateDocDependenciesTask(Type dbContextType, Type modelType, Type keyType, IEnumerable idPaths, object modelId) => backgroundJobClient.Enqueue( diff --git a/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs b/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs index 39282ff4..0406975f 100644 --- a/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs +++ b/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs @@ -20,13 +20,13 @@ public MigrateDbContextTaskFacade(IMigrateDbContextTask task) // Methods. [Queue(Queues.DB_MAINTENANCE)] - public Task RunAsync(Type dbContextType, string migrateOpId, PerformingContext context) + public Task RunAsync(Type dbContextType, string dbMigrationOpId, PerformingContext context) { var method = typeof(MigrateDbContextTask).GetMethod( nameof(MigrateDbContextTask.RunAsync), BindingFlags.Public | BindingFlags.Instance) .MakeGenericMethod(dbContextType); - return (Task)method.Invoke(task, new object[] { migrateOpId, context.BackgroundJob.Id }); + return (Task)method.Invoke(task, new object[] { dbMigrationOpId, context.BackgroundJob.Id }); } } } diff --git a/test/MongODM.Core.Tests/ExtendedClassMapSerializerTest.cs b/test/MongODM.Core.Tests/ExtendedClassMapSerializerTest.cs index 7230c977..5e8ab713 100644 --- a/test/MongODM.Core.Tests/ExtendedClassMapSerializerTest.cs +++ b/test/MongODM.Core.Tests/ExtendedClassMapSerializerTest.cs @@ -65,14 +65,14 @@ public SerializationTestElement( } // Fields. - private readonly Mock dbCacheMock; + private readonly Mock dbCacheMock; private readonly SemanticVersion documentVersion = new SemanticVersion("1.0.0"); private readonly Mock serializerModifierAccessorMock; // Constructor. public ExtendedClassMapSerializerTest() { - dbCacheMock = new Mock(); + dbCacheMock = new Mock(); dbCacheMock.Setup(c => c.LoadedModels.ContainsKey(It.IsAny())) .Returns(() => false); From 5e3ab4ea06e7129e9c00951e1551e9857fd0ea99 Mon Sep 17 00:00:00 2001 From: Mirko Da Corte Date: Sat, 18 Jul 2020 03:33:09 +0200 Subject: [PATCH 5/5] Fixes --- .../ServiceCollectionExtensions.cs | 1 + src/MongODM.Core/DbContext.cs | 61 +++++++++---------- src/MongODM.Core/IDbContext.cs | 6 ++ .../Migration/MongoCollectionMigration.cs | 9 ++- .../Migration/MongoDocumentMigration.cs | 11 ++-- .../Migration/MongoMigrationBase.cs | 4 +- .../DbMigrationOpAgg/DocumentMigrationLog.cs | 3 + .../DbMigrationOpAgg/IndexMigrationLog.cs | 2 +- .../Models/Internal/DbMigrationOperation.cs | 2 +- .../Internal/ModelMaps/OperationBaseMap.cs | 12 +--- .../Repositories/RepositoryRegister.cs | 6 +- .../Tasks/MigrateDbContextTask.cs | 2 + .../Utility/DbMigrationManager.cs | 2 +- .../Utility/IDbMigrationManager.cs | 2 +- .../Tasks/MigrateDbContextTaskFacade.cs | 2 +- 15 files changed, 67 insertions(+), 58 deletions(-) diff --git a/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs b/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs index eb7a05fa..89bc8e18 100644 --- a/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs +++ b/src/MongODM.AspNetCore/ServiceCollectionExtensions.cs @@ -69,6 +69,7 @@ public static MongODMConfiguration UseMongODM(); //tasks + services.TryAddTransient(); services.TryAddTransient(); //castle proxy generator diff --git a/src/MongODM.Core/DbContext.cs b/src/MongODM.Core/DbContext.cs index 8e484864..4caa8a0a 100644 --- a/src/MongODM.Core/DbContext.cs +++ b/src/MongODM.Core/DbContext.cs @@ -55,8 +55,9 @@ public DbContext( Database = Client.GetDatabase(options.DbName); // Initialize internal dependencies. - DocumentSchemaRegister.Initialize(this); DbMaintainer.Initialize(this); + DbMigrationManager.Initialize(this); + DocumentSchemaRegister.Initialize(this); RepositoryRegister.Initialize(this); // Initialize repositories. @@ -76,9 +77,6 @@ public DbContext( // Build and freeze document schema register. DocumentSchemaRegister.Freeze(); - - // Check for seeding. - SeedIfNeeded(); } // Public properties. @@ -140,45 +138,46 @@ public virtual async Task SaveChangesAsync(CancellationToken cancellationToken = // Commit updated models replacement. foreach (var model in ChangedModelsList) { - var modelType = model.GetType().BaseType; - if (RepositoryRegister.ModelCollectionRepositoryMap.ContainsKey(modelType)) //can't replace if is a file + var modelType = ProxyGenerator.PurgeProxyType(model.GetType()); + while (modelType != typeof(object)) //try to find right collection. Can't replace model if it is stored on gridfs { - var repository = RepositoryRegister.ModelCollectionRepositoryMap[modelType]; - await repository.ReplaceAsync(model).ConfigureAwait(false); + if (RepositoryRegister.ModelCollectionRepositoryMap.ContainsKey(modelType)) + { + var repository = RepositoryRegister.ModelCollectionRepositoryMap[modelType]; + await repository.ReplaceAsync(model).ConfigureAwait(false); + break; + } + else + { + modelType = modelType.BaseType; + } } } } - public Task StartSessionAsync(CancellationToken cancellationToken = default) => - Client.StartSessionAsync(cancellationToken: cancellationToken); - - // Protected methods. - protected virtual Task Seed() => - Task.CompletedTask; - - // Helpers. - private void SeedIfNeeded() + public async Task SeedIfNeededAsync() { // Check if already seeded. - var queryTask = DbOperations.QueryElementsAsync(elements => - elements.OfType().AnyAsync(sop => sop.DbContextName == Identifier)); - queryTask.ConfigureAwait(false); - queryTask.Wait(); - - //skip if already seeded - if (queryTask.Result) - return; + if (await DbOperations.QueryElementsAsync(elements => + elements.OfType() + .AnyAsync(sop => sop.DbContextName == Identifier)).ConfigureAwait(false)) + return false; // Seed. - var seedTask = Seed(); - seedTask.ConfigureAwait(false); - seedTask.Wait(); + await SeedAsync().ConfigureAwait(false); // Report operation. var seedOperation = new SeedOperation(this); - var createTask = DbOperations.CreateAsync(seedOperation); - createTask.ConfigureAwait(false); - createTask.Wait(); + await DbOperations.CreateAsync(seedOperation).ConfigureAwait(false); + + return true; } + + public Task StartSessionAsync(CancellationToken cancellationToken = default) => + Client.StartSessionAsync(cancellationToken: cancellationToken); + + // Protected methods. + protected virtual Task SeedAsync() => + Task.CompletedTask; } } \ No newline at end of file diff --git a/src/MongODM.Core/IDbContext.cs b/src/MongODM.Core/IDbContext.cs index 5cbe8ab6..94e752e5 100644 --- a/src/MongODM.Core/IDbContext.cs +++ b/src/MongODM.Core/IDbContext.cs @@ -95,6 +95,12 @@ public interface IDbContext /// Cancellation token Task SaveChangesAsync(CancellationToken cancellationToken = default); + /// + /// Seed database context if still not seeded + /// + /// True if seed has been executed. False otherwise + Task SeedIfNeededAsync(); + /// /// Start a new database transaction session. /// diff --git a/src/MongODM.Core/Migration/MongoCollectionMigration.cs b/src/MongODM.Core/Migration/MongoCollectionMigration.cs index 9b2237d1..81a7976e 100644 --- a/src/MongODM.Core/Migration/MongoCollectionMigration.cs +++ b/src/MongODM.Core/Migration/MongoCollectionMigration.cs @@ -22,7 +22,7 @@ public class MongoCollectionMigration converter; private readonly Func discriminator; private readonly IMongoCollection destinationCollection; - private readonly IMongoCollection sourceCollection; + private readonly ICollectionRepository _sourceCollection; // Constructor. public MongoCollectionMigration( @@ -38,12 +38,15 @@ public MongoCollectionMigration( if (destinationCollection is null) throw new ArgumentNullException(nameof(destinationCollection)); - this.sourceCollection = sourceCollection.Collection; + _sourceCollection = sourceCollection; this.destinationCollection = destinationCollection.Collection; this.converter = converter; this.discriminator = discriminator; } + // Properties. + public override ICollectionRepository SourceCollection => _sourceCollection; + // Methods. public override async Task MigrateAsync( int callbackEveryDocuments = 0, @@ -55,7 +58,7 @@ public override async Task MigrateAsync( // Migrate documents. var totMigratedDocuments = 0L; - await sourceCollection.Find(Builders.Filter.Empty, new FindOptions { NoCursorTimeout = true }) + await _sourceCollection.Collection.Find(Builders.Filter.Empty, new FindOptions { NoCursorTimeout = true }) .ForEachAsync(async model => { if (callbackEveryDocuments > 0 && diff --git a/src/MongODM.Core/Migration/MongoDocumentMigration.cs b/src/MongODM.Core/Migration/MongoDocumentMigration.cs index 59a758e1..f011a2b3 100644 --- a/src/MongODM.Core/Migration/MongoDocumentMigration.cs +++ b/src/MongODM.Core/Migration/MongoDocumentMigration.cs @@ -19,7 +19,7 @@ public class MongoDocumentMigration : MongoMigrationBase { // Fields. private readonly SemanticVersion minimumDocumentVersion; - private readonly IMongoCollection sourceCollection; + private readonly ICollectionRepository _sourceCollection; // Constructors. public MongoDocumentMigration( @@ -31,10 +31,13 @@ public MongoDocumentMigration( if (sourceCollection is null) throw new ArgumentNullException(nameof(sourceCollection)); - this.sourceCollection = sourceCollection.Collection; + _sourceCollection = sourceCollection; this.minimumDocumentVersion = minimumDocumentVersion; } + // Properties. + public override ICollectionRepository SourceCollection => _sourceCollection; + // Methods. public override async Task MigrateAsync( int callbackEveryDocuments = 0, @@ -71,7 +74,7 @@ public override async Task MigrateAsync( // Migrate documents. var totMigratedDocuments = 0L; - await sourceCollection.Find(filter, new FindOptions { NoCursorTimeout = true }) + await _sourceCollection.Collection.Find(filter, new FindOptions { NoCursorTimeout = true }) .ForEachAsync(async model => { if (callbackEveryDocuments > 0 && @@ -79,7 +82,7 @@ public override async Task MigrateAsync( callbackAsync != null) await callbackAsync.Invoke(totMigratedDocuments).ConfigureAwait(false); - await sourceCollection.ReplaceOneAsync(Builders.Filter.Eq(m => m.Id, model.Id), model).ConfigureAwait(false); + await _sourceCollection.Collection.ReplaceOneAsync(Builders.Filter.Eq(m => m.Id, model.Id), model).ConfigureAwait(false); totMigratedDocuments++; }, cancellationToken).ConfigureAwait(false); diff --git a/src/MongODM.Core/Migration/MongoMigrationBase.cs b/src/MongODM.Core/Migration/MongoMigrationBase.cs index 1643880e..7c64aff6 100644 --- a/src/MongODM.Core/Migration/MongoMigrationBase.cs +++ b/src/MongODM.Core/Migration/MongoMigrationBase.cs @@ -1,4 +1,5 @@ -using System; +using Etherna.MongODM.Repositories; +using System; using System.Threading; using System.Threading.Tasks; @@ -14,6 +15,7 @@ public MongoMigrationBase(string id) // Properties. public string Id { get; } + public abstract ICollectionRepository SourceCollection { get; } // Methods. /// diff --git a/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/DocumentMigrationLog.cs b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/DocumentMigrationLog.cs index 49477d93..a64b36b3 100644 --- a/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/DocumentMigrationLog.cs +++ b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/DocumentMigrationLog.cs @@ -6,17 +6,20 @@ public class DocumentMigrationLog : MigrationLogBase { // Constructors. public DocumentMigrationLog( + string collectionName, string documentMigrationId, ExecutionState state, long totMigratedDocs) : base(state) { + CollectionName = collectionName; DocumentMigrationId = documentMigrationId; TotMigratedDocs = totMigratedDocs; } protected DocumentMigrationLog() { } // Properties. + public virtual string CollectionName { get; protected set; } = default!; public virtual string DocumentMigrationId { get; protected set; } = default!; public virtual long TotMigratedDocs { get; protected set; } } diff --git a/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/IndexMigrationLog.cs b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/IndexMigrationLog.cs index c75d408d..28ccd38b 100644 --- a/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/IndexMigrationLog.cs +++ b/src/MongODM.Core/Models/Internal/DbMigrationOpAgg/IndexMigrationLog.cs @@ -1,6 +1,6 @@ namespace Etherna.MongODM.Models.Internal.DbMigrationOpAgg { - class IndexMigrationLog : MigrationLogBase + public class IndexMigrationLog : MigrationLogBase { // Constructors. public IndexMigrationLog( diff --git a/src/MongODM.Core/Models/Internal/DbMigrationOperation.cs b/src/MongODM.Core/Models/Internal/DbMigrationOperation.cs index 73e15cdb..e268aa87 100644 --- a/src/MongODM.Core/Models/Internal/DbMigrationOperation.cs +++ b/src/MongODM.Core/Models/Internal/DbMigrationOperation.cs @@ -30,7 +30,7 @@ protected DbMigrationOperation() { } // Properties. public virtual string? Author { get; protected set; } - public virtual DateTime CompletedDateTime { get; protected set; } + public virtual DateTime? CompletedDateTime { get; protected set; } public virtual Status CurrentStatus { get; protected set; } public virtual IEnumerable Logs { diff --git a/src/MongODM.Core/Models/Internal/ModelMaps/OperationBaseMap.cs b/src/MongODM.Core/Models/Internal/ModelMaps/OperationBaseMap.cs index 6a4be08d..6eab9092 100644 --- a/src/MongODM.Core/Models/Internal/ModelMaps/OperationBaseMap.cs +++ b/src/MongODM.Core/Models/Internal/ModelMaps/OperationBaseMap.cs @@ -1,8 +1,5 @@ using Etherna.MongODM.Serialization; using Etherna.MongODM.Serialization.Serializers; -using MongoDB.Bson; -using MongoDB.Bson.Serialization.IdGenerators; -using MongoDB.Bson.Serialization.Serializers; namespace Etherna.MongODM.Models.Internal.ModelMaps { @@ -12,14 +9,7 @@ public void Register(IDbContext dbContext) { dbContext.DocumentSchemaRegister.RegisterModelSchema( "0.20.0", //mongodm library's version - cm => - { - cm.AutoMap(); - - // Set Id representation. - cm.IdMemberMap.SetSerializer(new StringSerializer(BsonType.ObjectId)) - .SetIdGenerator(new StringObjectIdGenerator()); - }, + cm => cm.AutoMap(), initCustomSerializer: () => new ExtendedClassMapSerializer( dbContext.DbCache, diff --git a/src/MongODM.Core/Repositories/RepositoryRegister.cs b/src/MongODM.Core/Repositories/RepositoryRegister.cs index ad1dec50..f19d5dc4 100644 --- a/src/MongODM.Core/Repositories/RepositoryRegister.cs +++ b/src/MongODM.Core/Repositories/RepositoryRegister.cs @@ -34,8 +34,8 @@ public IReadOnlyDictionary ModelCollectionRepositor { var dbContextType = dbContext.GetType(); - //select ICollectionRepository<,> implementing properties - var repos = dbContextType.GetProperties(BindingFlags.Public | BindingFlags.Instance) + // Select ICollectionRepository<,> from dbcontext properties. + var repos = dbContextType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy) .Where(prop => { var propType = prop.PropertyType; @@ -53,7 +53,7 @@ public IReadOnlyDictionary ModelCollectionRepositor return false; }); - //construct register + // Initialize register. _modelCollectionRepositoryMap = repos.ToDictionary( prop => ((ICollectionRepository)prop.GetValue(dbContext)).GetModelType, prop => (ICollectionRepository)prop.GetValue(dbContext)); diff --git a/src/MongODM.Core/Tasks/MigrateDbContextTask.cs b/src/MongODM.Core/Tasks/MigrateDbContextTask.cs index 65a64b3c..0c27c2a1 100644 --- a/src/MongODM.Core/Tasks/MigrateDbContextTask.cs +++ b/src/MongODM.Core/Tasks/MigrateDbContextTask.cs @@ -36,6 +36,7 @@ public async Task RunAsync(string dbMigrationOpId, string taskId) async procDocs => { dbMigrationOp.AddLog(new DocumentMigrationLog( + docMigration.SourceCollection.Name, docMigration.Id, MigrationLogBase.ExecutionState.Executing, procDocs)); @@ -45,6 +46,7 @@ public async Task RunAsync(string dbMigrationOpId, string taskId) //ended document migration log dbMigrationOp.AddLog(new DocumentMigrationLog( + docMigration.SourceCollection.Name, docMigration.Id, result.Succeded ? MigrationLogBase.ExecutionState.Succeded : diff --git a/src/MongODM.Core/Utility/DbMigrationManager.cs b/src/MongODM.Core/Utility/DbMigrationManager.cs index 16823581..52db45db 100644 --- a/src/MongODM.Core/Utility/DbMigrationManager.cs +++ b/src/MongODM.Core/Utility/DbMigrationManager.cs @@ -9,7 +9,7 @@ namespace Etherna.MongODM.Utility { - public class DbMigrationManager : IDbMigrationManager, IDbContextInitializable + public class DbMigrationManager : IDbMigrationManager { // Fields. private IDbContext dbContext = default!; diff --git a/src/MongODM.Core/Utility/IDbMigrationManager.cs b/src/MongODM.Core/Utility/IDbMigrationManager.cs index ef0ae156..481992de 100644 --- a/src/MongODM.Core/Utility/IDbMigrationManager.cs +++ b/src/MongODM.Core/Utility/IDbMigrationManager.cs @@ -4,7 +4,7 @@ namespace Etherna.MongODM.Utility { - public interface IDbMigrationManager + public interface IDbMigrationManager : IDbContextInitializable { Task IsMigrationRunningAsync(); diff --git a/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs b/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs index 0406975f..3e9aa0c1 100644 --- a/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs +++ b/src/MongODM.Hangfire/Tasks/MigrateDbContextTaskFacade.cs @@ -20,7 +20,7 @@ public MigrateDbContextTaskFacade(IMigrateDbContextTask task) // Methods. [Queue(Queues.DB_MAINTENANCE)] - public Task RunAsync(Type dbContextType, string dbMigrationOpId, PerformingContext context) + public Task RunAsync(Type dbContextType, string dbMigrationOpId, PerformContext context) { var method = typeof(MigrateDbContextTask).GetMethod( nameof(MigrateDbContextTask.RunAsync), BindingFlags.Public | BindingFlags.Instance)