Skip to content

Commit

Permalink
This addresses the issue of scope management for dbcontext.
Browse files Browse the repository at this point in the history
  • Loading branch information
carlsixsmith-moj committed Jul 14, 2024
1 parent 3505444 commit 537defa
Show file tree
Hide file tree
Showing 64 changed files with 368 additions and 193 deletions.
5 changes: 4 additions & 1 deletion src/Application/Common/Interfaces/IApplicationDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
using Cfo.Cats.Domain.ValueObjects;
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace Cfo.Cats.Application.Common.Interfaces;

public interface IApplicationDbContext
{
public DatabaseFacade Database { get; }

DbSet<AuditTrail> AuditTrails { get; }
DbSet<Tenant> Tenants { get; }

Expand All @@ -35,5 +38,5 @@ public interface IApplicationDbContext
ChangeTracker ChangeTracker { get; }

DbSet<DataProtectionKey> DataProtectionKeys { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken);

}
6 changes: 6 additions & 0 deletions src/Application/Common/Interfaces/IDomainEventDispatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Cfo.Cats.Application.Common.Interfaces;

public interface IDomainEventDispatcher
{
Task DispatchEventsAsync(IApplicationDbContext context, CancellationToken cancellationToken = default);
}
10 changes: 10 additions & 0 deletions src/Application/Common/Interfaces/IUnitOfWork.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Cfo.Cats.Application.Common.Interfaces;

public interface IUnitOfWork
{
IApplicationDbContext DbContext { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
Task BeginTransactionAsync();
Task CommitTransactionAsync();
Task RollbackTransactionAsync();
}
15 changes: 13 additions & 2 deletions src/Application/DependencyInjection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,22 @@ public static IServiceCollection AddApplication(this IServiceCollection services
config.AddOpenBehavior(typeof(PerformanceBehaviour<,>));
config.AddOpenBehavior(typeof(UnhandledExceptionBehaviour<,>));
config.AddOpenBehavior(typeof(RequestExceptionProcessorBehavior<,>));
config.AddOpenBehavior(typeof(MemoryCacheBehaviour<,>));
// config.AddOpenBehavior(typeof(MemoryCacheBehaviour<,>)); // issues with caching means we need to turn it off for now
config.AddOpenBehavior(typeof(AuthorizationBehaviour<,>));
config.AddOpenBehavior(typeof(CacheInvalidationBehaviour<,>));
// config.AddOpenBehavior(typeof(CacheInvalidationBehaviour<,>)); // issues with caching means we need to turn it off for now
config.AddOpenBehavior(typeof(TransactionBehaviour<,>));
});

// Register a factory for creating new instances of Mediator with a new scope
services.AddTransient<Func<IMediator>>(sp =>
{
return () =>
{
var scope = sp.CreateScope();
return scope.ServiceProvider.GetRequiredService<IMediator>();
};
});

services.AddLazyCache();

return services;
Expand Down
11 changes: 4 additions & 7 deletions src/Application/Features/Assessments/Commands/BeginAssessment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ public CancellationTokenSource? SharedExpiryTokenSource

public class Handler : IRequestHandler<Command, Result<Guid>>
{
private readonly IApplicationDbContext _context;
private readonly IUnitOfWork _unitOfWork;
private readonly ICurrentUserService _currentUserService;
public Handler(IApplicationDbContext context, ICurrentUserService currentUserService)
public Handler(IUnitOfWork unitOfWork, ICurrentUserService currentUserService)
{
_context = context;
_unitOfWork = unitOfWork;
_currentUserService = currentUserService;

}

public async Task<Result<Guid>> Handle(Command request, CancellationToken cancellationToken)
Expand Down Expand Up @@ -70,9 +69,7 @@ public async Task<Result<Guid>> Handle(Command request, CancellationToken cancel
pa.SetPathwayScore(pathway.Title, -1);
}

_context.ParticipantAssessments.Add(pa);
await _context.SaveChangesAsync(cancellationToken);

_unitOfWork.DbContext.ParticipantAssessments.Add(pa);
return await Result<Guid>.SuccessAsync(assessment.Id);
}
}
Expand Down
12 changes: 5 additions & 7 deletions src/Application/Features/Assessments/Commands/SaveAssessment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ public class Command : ICacheInvalidatorRequest<Result>

public class Handler : IRequestHandler<Command, Result>
{
private readonly IApplicationDbContext _context;
private readonly IUnitOfWork _unitOfWork;

public Handler(IApplicationDbContext context)
public Handler(IUnitOfWork unitOfWork)
{
_context = context;
_unitOfWork = unitOfWork;

}

public async Task<Result> Handle(Command request, CancellationToken cancellationToken)
{
ParticipantAssessment pa = _context.ParticipantAssessments.FirstOrDefault(r => r.Id == request.Assessment.Id && r.ParticipantId == request.Assessment.ParticipantId)
ParticipantAssessment pa = _unitOfWork.DbContext.ParticipantAssessments.FirstOrDefault(r => r.Id == request.Assessment.Id && r.ParticipantId == request.Assessment.ParticipantId)
?? throw new NotFoundException(nameof(Assessment), new
{
request.Assessment.Id,
Expand All @@ -49,7 +49,7 @@ public async Task<Result> Handle(Command request, CancellationToken cancellation

if (request.Submit)
{
var details = await _context.Participants
var details = await _unitOfWork.DbContext.Participants
.Where(p => p.Id == request.Assessment.ParticipantId)
.Select(p =>
new
Expand All @@ -71,8 +71,6 @@ public async Task<Result> Handle(Command request, CancellationToken cancellation
pa.Submit();
}

await _context.SaveChangesAsync(cancellationToken);

return await Result.SuccessAsync();
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/Application/Features/Assessments/Queries/GetAssessment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ public class Query : IRequest<Result<Assessment>>

internal class Handler : IRequestHandler<Query, Result<Assessment>>
{
private readonly IApplicationDbContext _context;
public Handler(IApplicationDbContext context)
private readonly IUnitOfWork _unitOfWork;
public Handler(IUnitOfWork unitOfWork)
{
_context = context;
this._unitOfWork = unitOfWork;
}

public async Task<Result<Assessment>> Handle(Query request, CancellationToken cancellationToken)
{
var query = _context.ParticipantAssessments
var query = _unitOfWork.DbContext.ParticipantAssessments
.Where(p => p.ParticipantId == request.ParticipantId);

if (request.AssessmentId is not null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@ public async Task<Result<int>> Handle(AddEditKeyValueCommand request, Cancellati
_ = keyValue ?? throw new NotFoundException($"KeyValue Pair {request.Id} Not Found.");
keyValue = _mapper.Map(request, keyValue);
keyValue.AddDomainEvent(new KeyValueUpdatedDomainEvent(keyValue));
await _context.SaveChangesAsync(cancellationToken);
return await Result<int>.SuccessAsync(keyValue.Id);
}
else
{
var keyValue = _mapper.Map<KeyValue>(request);
keyValue.AddDomainEvent(new KeyValueUpdatedDomainEvent(keyValue));
_context.KeyValues.Add(keyValue);
await _context.SaveChangesAsync(cancellationToken);
return await Result<int>.SuccessAsync(keyValue.Id);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ namespace Cfo.Cats.Application.Features.KeyValues.Commands.Delete;

public class DeleteKeyValueCommandHandler(IApplicationDbContext context) : IRequestHandler<DeleteKeyValueCommand, Result<int>>
{

public async Task<Result<int>> Handle(DeleteKeyValueCommand request, CancellationToken cancellationToken)
{
var items = await context.KeyValues.Where(x => request.Id.Contains(x.Id)).ToListAsync(cancellationToken);
Expand All @@ -12,8 +11,6 @@ public async Task<Result<int>> Handle(DeleteKeyValueCommand request, Cancellatio
item.AddDomainEvent(changeEvent);
context.KeyValues.Remove(item);
}

var result = await context.SaveChangesAsync(cancellationToken);
return await Result<int>.SuccessAsync(result);
return await Result<int>.SuccessAsync(items.Count);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@ public class ImportKeyValuesCommandHandler :
IRequestHandler<ImportKeyValuesCommand, Result>
{
private readonly IValidator<AddEditKeyValueCommand> _addValidator;
private readonly IApplicationDbContext _context;
private readonly IUnitOfWork _unitOfWork;
private readonly IExcelService _excelService;
private readonly IStringLocalizer<ImportKeyValuesCommandHandler> _localizer;
private readonly IMapper _mapper;

public ImportKeyValuesCommandHandler(
IApplicationDbContext context,
IUnitOfWork unitOfWork,
IMapper mapper,
IExcelService excelService,
IStringLocalizer<ImportKeyValuesCommandHandler> localizer,
IValidator<AddEditKeyValueCommand> addValidator
)
{
_context = context;
_mapper = mapper;
_excelService = excelService;
_mapper = mapper;
_unitOfWork = unitOfWork;
_excelService = excelService;
_localizer = localizer;
_addValidator = addValidator;
}
Expand Down Expand Up @@ -71,15 +71,15 @@ public async Task<Result> Handle(ImportKeyValuesCommand request, CancellationTok
cancellationToken);
if (validationResult.IsValid)
{
var exist = await _context.KeyValues.AnyAsync(x => x.Name == item.Name && x.Value == item.Value,
var exist = await _unitOfWork.DbContext.KeyValues.AnyAsync(x => x.Name == item.Name && x.Value == item.Value,
cancellationToken);
if (exist)
{
continue;
}

item.AddDomainEvent(new KeyValueCreatedDomainEvent(item));
await _context.KeyValues.AddAsync(item, cancellationToken);
await _unitOfWork.DbContext.KeyValues.AddAsync(item, cancellationToken);
}
else
{
Expand All @@ -89,9 +89,12 @@ public async Task<Result> Handle(ImportKeyValuesCommand request, CancellationTok
}
}

if (errorsOccurred) return await Result.FailureAsync(errors.ToArray());
if (errorsOccurred)
{
return await Result.FailureAsync(errors.ToArray());
}

await _context.SaveChangesAsync(cancellationToken);

return await Result.SuccessAsync();
}
}
Expand Down
9 changes: 3 additions & 6 deletions src/Application/Features/Participants/Commands/AddConsent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ public class Command : IRequest<Result<string>>
public UploadRequest? UploadRequest { get; set; }
}

public class Handler(IApplicationDbContext context, IUploadService uploadService) : IRequestHandler<Command, Result<string>>
public class Handler(IUnitOfWork unitOfWork, IUploadService uploadService) : IRequestHandler<Command, Result<string>>
{
public async Task<Result<string>> Handle(Command request, CancellationToken cancellationToken)
{
// get the participant
var participant = await context.Participants.FindAsync(request.ParticipantId!, cancellationToken);
var participant = await unitOfWork.DbContext.Participants.FindAsync(request.ParticipantId!, cancellationToken);

if (participant == null)
{
Expand All @@ -41,10 +41,7 @@ public async Task<Result<string>> Handle(Command request, CancellationToken canc

participant.AddConsent(request.ConsentDate!.Value, document.Id);

context.Documents.Add(document);

await context.SaveChangesAsync(cancellationToken);

unitOfWork.DbContext.Documents.Add(document);
return result;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ public class Command : IRequest<Result<string>>
public UploadRequest? UploadRequest { get; set; }
}

public class Handler(IApplicationDbContext context, IUploadService uploadService)
public class Handler(IUnitOfWork unitOfWork, IUploadService uploadService)
: IRequestHandler<Command, Result<string>>
{

public async Task<Result<string>> Handle(Command request, CancellationToken cancellationToken)
{
var participant = await context.Participants.FindAsync(request.ParticipantId);
var participant = await unitOfWork.DbContext.Participants.FindAsync(request.ParticipantId);

if(participant == null)
{
Expand All @@ -44,10 +44,7 @@ public async Task<Result<string>> Handle(Command request, CancellationToken canc

participant.AddRightToWork(request.ValidFrom!.Value, request.ValidTo!.Value, document.Id);

context.Documents.Add(document);

await context.SaveChangesAsync(cancellationToken);

unitOfWork.DbContext.Documents.Add(document);
return result;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Cfo.Cats.Application.Features.Participants.Commands;
public static class CreateParticipant
{
[RequestAuthorize(Policy = PolicyNames.AllowEnrol)]
public class Command: ICacheInvalidatorRequest<Result<string>>
public class Command: IRequest<Result<string>>
{
/// <summary>
/// The CATS identifier
Expand All @@ -35,18 +35,17 @@ public override string ToString()
}
}

public class Handler(IApplicationDbContext dbContext, ICurrentUserService currentUserService)
public class Handler(IUnitOfWork unitOfWork, ICurrentUserService currentUserService)
: IRequestHandler<Command, Result<string>>
{
public async Task<Result<string>> Handle(Command request, CancellationToken cancellationToken)
{
var candidate = request.Candidate;
Participant participant = Participant.CreateFrom(candidate.Identifier, candidate.FirstName, candidate.LastName, candidate.DateOfBirth, request.ReferralSource!, request.ReferralComments);
Participant participant = Participant.CreateFrom(candidate.Identifier, candidate.FirstName, candidate.LastName, candidate.DateOfBirth,
request.ReferralSource!, request.ReferralComments);
participant.AssignTo(currentUserService.UserId);

dbContext.Participants.Add(participant);
await dbContext.SaveChangesAsync(cancellationToken);

await unitOfWork.DbContext.Participants.AddAsync(participant, cancellationToken);
return request.Identifier!;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ public CancellationTokenSource? SharedExpiryTokenSource
=> ParticipantCacheKey.SharedExpiryTokenSource();
}

public class Handler(IApplicationDbContext context)
public class Handler(IUnitOfWork unitOfWork)
: IRequestHandler<Command, Result<string>>
{
public async Task<Result<string>> Handle(Command request, CancellationToken cancellationToken)
{
Participant? participant = await context.Participants.FirstOrDefaultAsync(p => p.Id == request.Identifier, cancellationToken);
var participant = await unitOfWork.DbContext.Participants.FirstOrDefaultAsync(p => p.Id == request.Identifier, cancellationToken);
if (participant == null)
{
throw new NotFoundException("Cannot find participant", request.Identifier);
Expand All @@ -61,7 +61,6 @@ public async Task<Result<string>> Handle(Command request, CancellationToken canc
}

participant.SetEnrolmentLocation(request.EnrolmentLocation.Id, request.JustificationReason);
await context.SaveChangesAsync(cancellationToken);
return participant.Id;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,12 @@ public class Command : ICacheInvalidatorRequest<Result>
public CancellationTokenSource? SharedExpiryTokenSource => CandidatesCacheKey.SharedExpiryTokenSource();
}

public class Handler(IApplicationDbContext context) : IRequestHandler<Command, Result>
public class Handler(IUnitOfWork unitOfWork) : IRequestHandler<Command, Result>
{
public async Task<Result> Handle(Command request, CancellationToken cancellationToken)
{
var participant = await context.Participants.FindAsync(request.ParticipantId);
var participant = await unitOfWork.DbContext.Participants.FindAsync(request.ParticipantId);
participant!.TransitionTo(EnrolmentStatus.SubmittedToProviderStatus);
await context.SaveChangesAsync(cancellationToken);
// ReSharper disable once MethodHasAsyncOverload
return Result.Success();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

namespace Cfo.Cats.Application.Features.Participants.EventHandlers;

public class ParticipantCreatedEventHandler(IApplicationDbContext context) : INotificationHandler<ParticipantCreatedDomainEvent>
public class ParticipantCreatedEventHandler(IUnitOfWork unitOfWork) : INotificationHandler<ParticipantCreatedDomainEvent>
{
public async Task Handle(ParticipantCreatedDomainEvent notification, CancellationToken cancellationToken)
{
context.ParticipantEnrolmentHistories.Add(ParticipantEnrolmentHistory.Create(notification.Item.Id, EnrolmentStatus.PendingStatus));
await context.SaveChangesAsync(cancellationToken);
var history = ParticipantEnrolmentHistory.Create(notification.Item.Id, EnrolmentStatus.PendingStatus);
await unitOfWork.DbContext.ParticipantEnrolmentHistories.AddAsync(history, cancellationToken);
}
}
Loading

0 comments on commit 537defa

Please sign in to comment.