From 005913c1255a4297e7d45a2a3e072ff232277eba Mon Sep 17 00:00:00 2001 From: Johelvis Guzman Date: Thu, 26 Mar 2020 00:43:45 -0400 Subject: [PATCH] (GH-603) Added a new repository interception context object --- .../Interceptors/IRepositoryInterceptor.cs | 24 ++++----- .../RepositoryInterceptionContext.cs | 33 ++++++++++++ .../Interceptors/RepositoryInterceptorBase.cs | 24 ++++----- .../RepositoryBase.cs | 54 ++++++++++++------- .../TestRepositoryTimeStampInterceptor.cs | 16 +++--- .../Interceptor/RepositoryInterceptorTests.cs | 24 ++++----- 6 files changed, 113 insertions(+), 62 deletions(-) create mode 100644 src/DotNetToolkit.Repository/Configuration/Interceptors/RepositoryInterceptionContext.cs diff --git a/src/DotNetToolkit.Repository/Configuration/Interceptors/IRepositoryInterceptor.cs b/src/DotNetToolkit.Repository/Configuration/Interceptors/IRepositoryInterceptor.cs index 62938d73..53a8ac0b 100644 --- a/src/DotNetToolkit.Repository/Configuration/Interceptors/IRepositoryInterceptor.cs +++ b/src/DotNetToolkit.Repository/Configuration/Interceptors/IRepositoryInterceptor.cs @@ -12,48 +12,48 @@ public interface IRepositoryInterceptor /// An activity method which is executed when adding an entity to the repository. /// /// The type of the entity. - /// The entity. - void AddExecuting(TEntity entity); + /// The interception context which includes information for the current operation. + void AddExecuting(RepositoryInterceptionContext interceptionContext) where TEntity : class; /// /// An activity method which is executed when deleting an entity from the repository. /// /// The type of the entity. - /// The entity. - void DeleteExecuting(TEntity entity); + /// The interception context which includes information for the current operation. + void DeleteExecuting(RepositoryInterceptionContext interceptionContext) where TEntity : class; /// /// An activity method which is executed when updating an entity in the repository. /// /// The type of the entity. - /// The entity. - void UpdateExecuting(TEntity entity); + /// The interception context which includes information for the current operation. + void UpdateExecuting(RepositoryInterceptionContext interceptionContext) where TEntity : class; /// /// Asynchronously an activity method which is executed when adding an entity to the repository. /// /// The type of the entity. - /// The entity. + /// The interception context which includes information for the current operation. /// A to observe while waiting for the task to complete. /// The that represents the asynchronous operation. - Task AddExecutingAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()); + Task AddExecutingAsync(RepositoryInterceptionContext interceptionContext, CancellationToken cancellationToken = new CancellationToken()) where TEntity : class; /// /// Asynchronously an activity method which is executed when deleting an entity from the repository. /// /// The type of the entity. - /// The entity. + /// The interception context which includes information for the current operation. /// A to observe while waiting for the task to complete. /// The that represents the asynchronous operation. - Task DeleteExecutingAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()); + Task DeleteExecutingAsync(RepositoryInterceptionContext interceptionContext, CancellationToken cancellationToken = new CancellationToken()) where TEntity : class; /// /// Asynchronously an activity method which is executed when updating an entity in the repository. /// /// The type of the entity. - /// The entity. + /// The interception context which includes information for the current operation. /// A to observe while waiting for the task to complete. /// The that represents the asynchronous operation. - Task UpdateExecutingAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()); + Task UpdateExecutingAsync(RepositoryInterceptionContext interceptionContext, CancellationToken cancellationToken = new CancellationToken()) where TEntity : class; } } diff --git a/src/DotNetToolkit.Repository/Configuration/Interceptors/RepositoryInterceptionContext.cs b/src/DotNetToolkit.Repository/Configuration/Interceptors/RepositoryInterceptionContext.cs new file mode 100644 index 00000000..8e4bfdaa --- /dev/null +++ b/src/DotNetToolkit.Repository/Configuration/Interceptors/RepositoryInterceptionContext.cs @@ -0,0 +1,33 @@ +namespace DotNetToolkit.Repository.Configuration.Interceptors +{ + using JetBrains.Annotations; + using Utility; + + /// + /// Represents contextual information associated with calls into . + /// + /// The type of the entity associated to the current operation. + public class RepositoryInterceptionContext where TEntity : class + { + /// + /// Gets the entity associated with the current operation. + /// + public TEntity Entity { get; } + + /// + /// Gets the context. + /// + public IRepositoryContext Context { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The entity. + /// The context. + public RepositoryInterceptionContext([NotNull] TEntity entity, [NotNull] IRepositoryContext context) + { + Entity = Guard.NotNull(entity, nameof(entity)); + Context = Guard.NotNull(context, nameof(context)); + } + } +} diff --git a/src/DotNetToolkit.Repository/Configuration/Interceptors/RepositoryInterceptorBase.cs b/src/DotNetToolkit.Repository/Configuration/Interceptors/RepositoryInterceptorBase.cs index ae57d3df..d01d5214 100644 --- a/src/DotNetToolkit.Repository/Configuration/Interceptors/RepositoryInterceptorBase.cs +++ b/src/DotNetToolkit.Repository/Configuration/Interceptors/RepositoryInterceptorBase.cs @@ -13,48 +13,48 @@ public abstract class RepositoryInterceptorBase : IRepositoryInterceptor /// An activity method which is executed when adding an entity to the repository. /// /// The type of the entity. - /// The entity. - public virtual void AddExecuting(TEntity entity) { } + /// The interception context which includes information for the current operation. + public virtual void AddExecuting(RepositoryInterceptionContext interceptionContext) where TEntity : class {} /// /// An activity method which is executed when deleting an entity from the repository. /// /// The type of the entity. - /// The entity. - public virtual void DeleteExecuting(TEntity entity) { } + /// The interception context which includes information for the current operation. + public virtual void DeleteExecuting(RepositoryInterceptionContext interceptionContext) where TEntity : class {} /// /// An activity method which is executed when updating an entity in the repository. /// /// The type of the entity. - /// The entity. - public virtual void UpdateExecuting(TEntity entity) { } + /// The interception context which includes information for the current operation. + public virtual void UpdateExecuting(RepositoryInterceptionContext interceptionContext) where TEntity : class {} /// /// Asynchronously an activity method which is executed when adding an entity to the repository. /// /// The type of the entity. - /// The entity. + /// The interception context which includes information for the current operation. /// A to observe while waiting for the task to complete. /// The that represents the asynchronous operation. - public virtual Task AddExecutingAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) => Task.FromResult(0); + public virtual Task AddExecutingAsync(RepositoryInterceptionContext interceptionContext, CancellationToken cancellationToken = new CancellationToken()) where TEntity : class => Task.FromResult(0); /// /// Asynchronously an activity method which is executed when deleting an entity from the repository. /// /// The type of the entity. - /// The entity. + /// The interception context which includes information for the current operation. /// A to observe while waiting for the task to complete. /// The that represents the asynchronous operation. - public virtual Task DeleteExecutingAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) => Task.FromResult(0); + public virtual Task DeleteExecutingAsync(RepositoryInterceptionContext interceptionContext, CancellationToken cancellationToken = new CancellationToken()) where TEntity : class => Task.FromResult(0); /// /// Asynchronously an activity method which is executed when updating an entity in the repository. /// /// The type of the entity. - /// The entity. + /// The interception context which includes information for the current operation. /// A to observe while waiting for the task to complete. /// The that represents the asynchronous operation. - public virtual Task UpdateExecutingAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) => Task.FromResult(0); + public virtual Task UpdateExecutingAsync(RepositoryInterceptionContext interceptionContext, CancellationToken cancellationToken = new CancellationToken()) where TEntity : class => Task.FromResult(0); } } diff --git a/src/DotNetToolkit.Repository/RepositoryBase.cs b/src/DotNetToolkit.Repository/RepositoryBase.cs index ffd960c4..eb0dcc31 100644 --- a/src/DotNetToolkit.Repository/RepositoryBase.cs +++ b/src/DotNetToolkit.Repository/RepositoryBase.cs @@ -1430,10 +1430,11 @@ public void Add([NotNull] TEntity entity) InterceptError(() => Guard.NotNull(entity, nameof(entity))); - Intercept(x => x.AddExecuting(entity)); - UseContext(context => { + Intercept(x => x.AddExecuting( + new RepositoryInterceptionContext(entity, context))); + context.Add(entity); context.SaveChanges(); }); @@ -1457,7 +1458,8 @@ public void Add([NotNull] IEnumerable entities) { foreach (var entity in entities) { - Intercept(x => x.AddExecuting(entity)); + Intercept(x => x.AddExecuting( + new RepositoryInterceptionContext(entity, context))); context.Add(entity); } @@ -1480,10 +1482,11 @@ public void Update([NotNull] TEntity entity) InterceptError(() => Guard.NotNull(entity, nameof(entity))); - Intercept(x => x.UpdateExecuting(entity)); - UseContext(context => { + Intercept(x => x.UpdateExecuting( + new RepositoryInterceptionContext(entity, context))); + context.Update(entity); context.SaveChanges(); }); @@ -1507,7 +1510,8 @@ public void Update([NotNull] IEnumerable entities) { foreach (var entity in entities) { - Intercept(x => x.UpdateExecuting(entity)); + Intercept(x => x.UpdateExecuting( + new RepositoryInterceptionContext(entity, context))); context.Update(entity); } @@ -1530,10 +1534,11 @@ public void Delete([NotNull] TEntity entity) InterceptError(() => Guard.NotNull(entity, nameof(entity))); - Intercept(x => x.DeleteExecuting(entity)); - UseContext(context => { + Intercept(x => x.DeleteExecuting( + new RepositoryInterceptionContext(entity, context))); + context.Remove(entity); context.SaveChanges(); }); @@ -1591,7 +1596,8 @@ public void Delete([NotNull] IEnumerable entities) { foreach (var entity in entities) { - Intercept(x => x.DeleteExecuting(entity)); + Intercept(x => x.DeleteExecuting( + new RepositoryInterceptionContext(entity, context))); context.Remove(entity); } @@ -2175,10 +2181,12 @@ Task Getter() => cancellationToken.ThrowIfCancellationRequested(); }); - await InterceptAsync(x => x.AddExecutingAsync(entity, cancellationToken)); - await UseContextAsync(async context => { + await InterceptAsync(x => x.AddExecutingAsync( + new RepositoryInterceptionContext(entity, context), + cancellationToken)); + context.Add(entity); await context.SaveChangesAsync(cancellationToken); }); @@ -2209,7 +2217,9 @@ await UseContextAsync(async context => { foreach (var entity in entities) { - await InterceptAsync(x => x.AddExecutingAsync(entity, cancellationToken)); + await InterceptAsync(x => x.AddExecutingAsync( + new RepositoryInterceptionContext(entity, context), + cancellationToken)); context.Add(entity); } @@ -2239,10 +2249,12 @@ await UseContextAsync(async context => cancellationToken.ThrowIfCancellationRequested(); }); - await InterceptAsync(x => x.UpdateExecutingAsync(entity, cancellationToken)); - await UseContextAsync(async context => { + await InterceptAsync(x => x.UpdateExecutingAsync( + new RepositoryInterceptionContext(entity, context), + cancellationToken)); + context.Update(entity); await context.SaveChangesAsync(cancellationToken); }); @@ -2273,7 +2285,9 @@ await UseContextAsync(async context => { foreach (var entity in entities) { - await InterceptAsync(x => x.UpdateExecutingAsync(entity, cancellationToken)); + await InterceptAsync(x => x.UpdateExecutingAsync( + new RepositoryInterceptionContext(entity, context), + cancellationToken)); context.Update(entity); } @@ -2303,10 +2317,12 @@ await UseContextAsync(async context => cancellationToken.ThrowIfCancellationRequested(); }); - await InterceptAsync(x => x.DeleteExecutingAsync(entity, cancellationToken)); - await UseContextAsync(async context => { + await InterceptAsync(x => x.DeleteExecutingAsync( + new RepositoryInterceptionContext(entity, context), + cancellationToken)); + context.Remove(entity); await context.SaveChangesAsync(cancellationToken); }); @@ -2377,7 +2393,9 @@ await UseContextAsync(async context => { foreach (var entity in entities) { - await InterceptAsync(x => x.DeleteExecutingAsync(entity, cancellationToken)); + await InterceptAsync(x => x.DeleteExecutingAsync( + new RepositoryInterceptionContext(entity, context), + cancellationToken)); context.Remove(entity); } diff --git a/test/DotNetToolkit.Repository.Integration.Test/Data/TestRepositoryTimeStampInterceptor.cs b/test/DotNetToolkit.Repository.Integration.Test/Data/TestRepositoryTimeStampInterceptor.cs index c634a3d4..e23583a1 100644 --- a/test/DotNetToolkit.Repository.Integration.Test/Data/TestRepositoryTimeStampInterceptor.cs +++ b/test/DotNetToolkit.Repository.Integration.Test/Data/TestRepositoryTimeStampInterceptor.cs @@ -23,9 +23,9 @@ public TestRepositoryTimeStampInterceptor(string loggedInUser) _user = loggedInUser; } - public override void AddExecuting(TEntity entity) + public override void AddExecuting(RepositoryInterceptionContext interceptionContext) { - if (entity is IHaveTimeStamp haveStamp) + if (interceptionContext.Entity is IHaveTimeStamp haveStamp) { var currentTime = DateTime.UtcNow; @@ -36,9 +36,9 @@ public override void AddExecuting(TEntity entity) } } - public override void UpdateExecuting(TEntity entity) + public override void UpdateExecuting(RepositoryInterceptionContext interceptionContext) { - if (entity is IHaveTimeStamp haveStamp) + if (interceptionContext.Entity is IHaveTimeStamp haveStamp) { var currentTime = DateTime.UtcNow; @@ -47,9 +47,9 @@ public override void UpdateExecuting(TEntity entity) } } - public override Task AddExecutingAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) + public override Task AddExecutingAsync(RepositoryInterceptionContext interceptionContext, CancellationToken cancellationToken = new CancellationToken()) { - if (entity is IHaveTimeStamp haveStamp) + if (interceptionContext.Entity is IHaveTimeStamp haveStamp) { var currentTime = DateTime.UtcNow; @@ -62,9 +62,9 @@ public override void UpdateExecuting(TEntity entity) return Task.FromResult(0); } - public override Task UpdateExecutingAsync(TEntity entity, CancellationToken cancellationToken = new CancellationToken()) + public override Task UpdateExecutingAsync(RepositoryInterceptionContext interceptionContext, CancellationToken cancellationToken = new CancellationToken()) { - if (entity is IHaveTimeStamp haveStamp) + if (interceptionContext.Entity is IHaveTimeStamp haveStamp) { var currentTime = DateTime.UtcNow; diff --git a/test/DotNetToolkit.Repository.Integration.Test/Tests/Interceptor/RepositoryInterceptorTests.cs b/test/DotNetToolkit.Repository.Integration.Test/Tests/Interceptor/RepositoryInterceptorTests.cs index 102e8939..79b9ca1c 100644 --- a/test/DotNetToolkit.Repository.Integration.Test/Tests/Interceptor/RepositoryInterceptorTests.cs +++ b/test/DotNetToolkit.Repository.Integration.Test/Tests/Interceptor/RepositoryInterceptorTests.cs @@ -28,11 +28,11 @@ public void Add() var repo = new Repository(options); - mock.Verify(x => x.AddExecuting(It.IsAny()), Times.Never); + mock.Verify(x => x.AddExecuting(It.IsAny>()), Times.Never); repo.Add(entity); - mock.Verify(x => x.AddExecuting(It.Is(z => z == entity)), Times.Once); + mock.Verify(x => x.AddExecuting(It.Is>(z => z.Entity == entity)), Times.Once); } [Fact] @@ -50,11 +50,11 @@ public void Update() repo.Add(entity); - mock.Verify(x => x.UpdateExecuting(It.IsAny()), Times.Never); + mock.Verify(x => x.UpdateExecuting(It.IsAny>()), Times.Never); repo.Update(entity); - mock.Verify(x => x.UpdateExecuting(It.Is(z => z == entity)), Times.Once); + mock.Verify(x => x.UpdateExecuting(It.Is>(z => z.Entity == entity)), Times.Once); } [Fact] @@ -72,11 +72,11 @@ public void Delete() repo.Add(entity); - mock.Verify(x => x.DeleteExecuting(It.IsAny()), Times.Never); + mock.Verify(x => x.DeleteExecuting(It.IsAny>()), Times.Never); repo.Delete(entity); - mock.Verify(x => x.DeleteExecuting(It.Is(z => z == entity)), Times.Once); + mock.Verify(x => x.DeleteExecuting(It.Is>(z => z.Entity == entity)), Times.Once); } [Fact] @@ -178,11 +178,11 @@ public async Task AddAsync() var repo = new Repository(options); - mock.Verify(x => x.AddExecutingAsync(It.IsAny(), It.IsAny()), Times.Never); + mock.Verify(x => x.AddExecutingAsync(It.IsAny>(), It.IsAny()), Times.Never); await repo.AddAsync(entity); - mock.Verify(x => x.AddExecutingAsync(It.Is(z => z == entity), It.IsAny()), Times.Once); + mock.Verify(x => x.AddExecutingAsync(It.Is>(z => z.Entity == entity), It.IsAny()), Times.Once); } [Fact] @@ -200,11 +200,11 @@ public async Task UpdateAsync() await repo.AddAsync(entity); - mock.Verify(x => x.UpdateExecutingAsync(It.IsAny(), It.IsAny()), Times.Never); + mock.Verify(x => x.UpdateExecutingAsync(It.IsAny>(), It.IsAny()), Times.Never); await repo.UpdateAsync(entity); - mock.Verify(x => x.UpdateExecutingAsync(It.Is(z => z == entity), It.IsAny()), Times.Once); + mock.Verify(x => x.UpdateExecutingAsync(It.Is>(z => z.Entity == entity), It.IsAny()), Times.Once); } [Fact] @@ -222,11 +222,11 @@ public async Task DeleteAsync() await repo.AddAsync(entity); - mock.Verify(x => x.DeleteExecutingAsync(It.IsAny(), It.IsAny()), Times.Never); + mock.Verify(x => x.DeleteExecutingAsync(It.IsAny>(), It.IsAny()), Times.Never); await repo.DeleteAsync(entity); - mock.Verify(x => x.DeleteExecutingAsync(It.Is(z => z == entity), It.IsAny()), Times.Once); + mock.Verify(x => x.DeleteExecutingAsync(It.Is>(z => z.Entity == entity), It.IsAny()), Times.Once); } [Fact]