Skip to content

Commit

Permalink
Feature/86 linq2db support (#97)
Browse files Browse the repository at this point in the history
* Nuget version bump.

* WARNING: Breaking changes. Refactored Repository interfaces to simplify them and prepare for other Repository APIs. Added beginings of Linq2Db.

* Implemented Linq2Db Repository. Still some work to do though.

* Refactored ChangeTracking to Event Tracking for business entities to more closely represent what we're doing.

* Modified sln to remove deprecated projects.

* A nearly complete implementation of the Linq2DbRepository. Still need to find a solution for FindAsync(object primaryKey) though.

* Added bulk of Linq2Db Integration tests. Still need some work on mappings.

* Fixing bugs with integration tests.

* Reworked how Linq2Db gets instantiated to allow for DI. Also added some integration test mappings. About half of test working now.

* More changes.

* Simplified the eager loading interface with Include and ThenInclude methods for repositories. Also removed some code bloat related to all that. GraphRepositoryBase now inherits LinqRepositoryBase which also improves DRYness of code.

* Removed invalid integration tests.

* Changes to linq2db testing.

* Updated to .NET 7 and latest dependencies.

* Updated Nuget versions.

* Update README.md

* Created override for PaginatedListModel which allows for the possibility of decoupling logic related to domain from DTO.

* Updating nuget packages.

* Utilizing EF for all test project persistence.

* Merged w/ dotnet7 changes in main. This is a checkpoint and not stable.

* Fixed Linq2Db upgrade issues.

* Fixed linq2db upgrade issues.

* Adding ignored file.

* Updated dependencies

* Refined EFCore Repository tests.

* Checkpoint. Refactoring to use common data preparations across repository implementations. Should make testing easier.

* Updated repository unit tests.

* Updated dependencies.

* Fixed up Dapper and EF unit testing issues.

* Checkpoint.

* Updated all the linq2db unit tests.

* Documented known issue in Linq2Db.

* Fixed not implemented unit test.

---------

Co-authored-by: jasonmwebb-lv <[email protected]>
  • Loading branch information
JasonMWebb and jasonmwebb-lv authored Nov 6, 2023
1 parent 0ee9c8f commit e6c7300
Show file tree
Hide file tree
Showing 132 changed files with 2,537 additions and 2,478 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -337,4 +337,5 @@ ASALocalRun/
.localhistory/

# BeatPulse healthcheck temp database
healthchecksdb
healthchecksdb
/Src/RCommon.Persistence.EfCore/IEFCoreConfiguration.cs
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# RCommon Application Framework

## Overview
RCommon was originally born as the (now abandoned) [NCommon](https://github.com/riteshrao/ncommon "NCommon") project but was resurrected out of the need to generate a productive, yet a relatively sound (architecturally speaking) application. Architectural patterns are used to implement some of the most commonly used tools in the .NET 6 stack. The primary goals of this framework are:
RCommon was originally born as the (now abandoned) [NCommon](https://github.com/riteshrao/ncommon "NCommon") project but was resurrected out of the need to generate a productive, yet a relatively sound (architecturally speaking) application. Architectural patterns are used to implement some of the most commonly used tools in the .NET 7 stack. The primary goals of this framework are:
1. Future proofing applications against changing architectural or infrastructure needs.
2. Solve common problems under the presentation layer. Presentation frameworks are something else entirely. We try to keep everything nice under the hood. Cross cutting concerns, persistence strategies, transaction management, validation, business rules, exception management, and logging is where we want to shine.
3. Code testability. We try to limit the "magic" used. Things like dependency injection are used but in a very straightforward manner. Unit tests, and integration tests should be implemented to the highest degree possible. Afterall, we want the applications you build on top of this to work :)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>disable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>09f081bb-4302-41b2-bfd9-ffcbade132d2</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MediatR" Version="11.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.10">
<PackageReference Include="MediatR" Version="12.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.13">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<Nullable>disable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.0" />
<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="Bogus" Version="34.0.2" />
<PackageReference Include="FluentAssertions" Version="6.8.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
<PackageReference Include="Moq" Version="4.18.2" />
<PackageReference Include="Shouldly" Version="4.1.0" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageReference Include="Moq" Version="4.20.69" />
<PackageReference Include="Shouldly" Version="4.2.1" />
<PackageReference Include="nunit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
<PackageReference Include="coverlet.collector" Version="3.1.2">
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public CreateLeaveTypeCommandHandlerTests()
_mapper = mapperConfig.CreateMapper();

var testData = new List<LeaveType>();
var mock = new Mock<IFullFeaturedRepository<LeaveType>>();
var mock = new Mock<IGraphRepository<LeaveType>>();
mock.Setup(x => x.AddAsync(TestDataActions.CreateLeaveTypeStub(), CancellationToken.None))
.Returns(() => Task.FromResult(new BaseCommandResponse()));
_handler = new CreateLeaveTypeCommandHandler(_mapper, mock.Object);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task GetLeaveTypeListTest()
{
testData.Add(TestDataActions.CreateLeaveTypeStub());
}
var mock = new Mock<IFullFeaturedRepository<LeaveType>>();
var mock = new Mock<IGraphRepository<LeaveType>>();
mock.Setup(x => x.FindAsync(x=>true, CancellationToken.None))
.Returns(() => Task.FromResult(testData as ICollection<LeaveType>));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static class ApplicationServicesRegistration
public static IServiceCollection ConfigureApplicationServices(this IServiceCollection services)
{
services.AddAutoMapper(Assembly.GetExecutingAssembly());
services.AddMediatR(Assembly.GetExecutingAssembly());
services.AddMediatR(x=>x.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));

return services;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ namespace HR.LeaveManagement.Application.Features.LeaveAllocations.Handlers.Comm
{
public class CreateLeaveAllocationCommandHandler : IRequestHandler<CreateLeaveAllocationCommand, BaseCommandResponse>
{
private readonly IFullFeaturedRepository<LeaveType> _leaveTypeRepository;
private readonly IFullFeaturedRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IGraphRepository<LeaveType> _leaveTypeRepository;
private readonly IGraphRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IUserService _userService;
private readonly IMapper _mapper;

public CreateLeaveAllocationCommandHandler(IFullFeaturedRepository<LeaveType> leaveTypeRepository,
IFullFeaturedRepository<LeaveAllocation> leaveAllocationRepository,
public CreateLeaveAllocationCommandHandler(IGraphRepository<LeaveType> leaveTypeRepository,
IGraphRepository<LeaveAllocation> leaveAllocationRepository,
IUserService userService,
IMapper mapper)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,24 @@ namespace HR.LeaveManagement.Application.Features.LeaveAllocations.Handlers.Comm
{
public class DeleteLeaveAllocationCommandHandler : IRequestHandler<DeleteLeaveAllocationCommand>
{
private readonly IFullFeaturedRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IGraphRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IMapper _mapper;

public DeleteLeaveAllocationCommandHandler(IFullFeaturedRepository<LeaveAllocation> leaveAllocationRepository, IMapper mapper)
public DeleteLeaveAllocationCommandHandler(IGraphRepository<LeaveAllocation> leaveAllocationRepository, IMapper mapper)
{
this._leaveAllocationRepository = leaveAllocationRepository;
this._leaveAllocationRepository.DataStoreName = "LeaveManagement";
_mapper = mapper;
}

public async Task<Unit> Handle(DeleteLeaveAllocationCommand request, CancellationToken cancellationToken)
public async Task Handle(DeleteLeaveAllocationCommand request, CancellationToken cancellationToken)
{
var leaveAllocation = await _leaveAllocationRepository.FindAsync(request.Id);

if (leaveAllocation == null)
throw new NotFoundException(nameof(LeaveAllocation), request.Id);

await _leaveAllocationRepository.DeleteAsync(leaveAllocation);
return Unit.Value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ namespace HR.LeaveManagement.Application.Features.LeaveAllocations.Handlers.Comm
{
public class UpdateLeaveAllocationCommandHandler : IRequestHandler<UpdateLeaveAllocationCommand, Unit>
{
private readonly IFullFeaturedRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IGraphRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IReadOnlyRepository<LeaveType> _leaveTypeRepository;
private readonly IMapper _mapper;

public UpdateLeaveAllocationCommandHandler(IFullFeaturedRepository<LeaveAllocation> leaveAllocationRepository,
public UpdateLeaveAllocationCommandHandler(IGraphRepository<LeaveAllocation> leaveAllocationRepository,
IReadOnlyRepository<LeaveType> leaveTypeRepository,
IMapper mapper)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ namespace HR.LeaveManagement.Application.Features.LeaveAllocations.Handlers.Quer
{
public class GetLeaveAllocationDetailRequestHandler : IRequestHandler<GetLeaveAllocationDetailRequest, LeaveAllocationDto>
{
private readonly IFullFeaturedRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IGraphRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IMapper _mapper;

public GetLeaveAllocationDetailRequestHandler(IFullFeaturedRepository<LeaveAllocation> leaveAllocationRepository, IMapper mapper)
public GetLeaveAllocationDetailRequestHandler(IGraphRepository<LeaveAllocation> leaveAllocationRepository, IMapper mapper)
{
_leaveAllocationRepository = leaveAllocationRepository;
this._leaveAllocationRepository.DataStoreName = "LeaveManagement";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ namespace HR.LeaveManagement.Application.Features.LeaveAllocations.Handlers.Quer
{
public class GetLeaveAllocationListRequestHandler : IRequestHandler<GetLeaveAllocationListRequest, List<LeaveAllocationDto>>
{
private readonly IFullFeaturedRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IGraphRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IMapper _mapper;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUserService _userService;

public GetLeaveAllocationListRequestHandler(IFullFeaturedRepository<LeaveAllocation> leaveAllocationRepository,
public GetLeaveAllocationListRequestHandler(IGraphRepository<LeaveAllocation> leaveAllocationRepository,
IMapper mapper,
IHttpContextAccessor httpContextAccessor,
IUserService userService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ public class CreateLeaveRequestCommandHandler : IRequestHandler<CreateLeaveReque
private readonly IOptions<SendGridEmailSettings> _emailSettings;
private readonly IMapper _mapper;
private readonly IReadOnlyRepository<LeaveType> _leaveTypeRepository;
private readonly IFullFeaturedRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IFullFeaturedRepository<LeaveRequest> _leaveRequestRepository;
private readonly IGraphRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IGraphRepository<LeaveRequest> _leaveRequestRepository;

public CreateLeaveRequestCommandHandler(
IReadOnlyRepository<LeaveType> leaveTypeRepository,
IFullFeaturedRepository<LeaveAllocation> leaveAllocationRepository,
IFullFeaturedRepository<LeaveRequest> leaveRequestRepository,
IGraphRepository<LeaveAllocation> leaveAllocationRepository,
IGraphRepository<LeaveRequest> leaveRequestRepository,
IEmailService emailSender,
ICurrentUser currentUser,
IOptions<SendGridEmailSettings> emailSettings,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,22 @@ namespace HR.LeaveManagement.Application.Features.LeaveRequests.Handlers.Command
{
public class DeleteLeaveRequestCommandHandler : IRequestHandler<DeleteLeaveRequestCommand>
{
private readonly IFullFeaturedRepository<LeaveRequest> _leaveRequestRepository;
private readonly IGraphRepository<LeaveRequest> _leaveRequestRepository;

public DeleteLeaveRequestCommandHandler(IFullFeaturedRepository<LeaveRequest> leaveRequestRepository)
public DeleteLeaveRequestCommandHandler(IGraphRepository<LeaveRequest> leaveRequestRepository)
{
this._leaveRequestRepository = leaveRequestRepository;
this._leaveRequestRepository.DataStoreName = "LeaveManagement";
}

public async Task<Unit> Handle(DeleteLeaveRequestCommand request, CancellationToken cancellationToken)
public async Task Handle(DeleteLeaveRequestCommand request, CancellationToken cancellationToken)
{
var leaveRequest = await _leaveRequestRepository.FindAsync(request.Id);

if (leaveRequest == null)
throw new NotFoundException(nameof(LeaveRequest), request.Id);

await _leaveRequestRepository.DeleteAsync(leaveRequest);
return Unit.Value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ namespace HR.LeaveManagement.Application.Features.LeaveRequests.Handlers.Command
{
public class UpdateLeaveRequestCommandHandler : IRequestHandler<UpdateLeaveRequestCommand, Unit>
{
private readonly IFullFeaturedRepository<LeaveRequest> _leaveRequestRepository;
private readonly IGraphRepository<LeaveRequest> _leaveRequestRepository;
private readonly IReadOnlyRepository<LeaveType> _leaveTypeRepository;
private readonly IFullFeaturedRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IGraphRepository<LeaveAllocation> _leaveAllocationRepository;
private readonly IMapper _mapper;

public UpdateLeaveRequestCommandHandler(
IFullFeaturedRepository<LeaveRequest> leaveRequestRepository,
IGraphRepository<LeaveRequest> leaveRequestRepository,
IReadOnlyRepository<LeaveType> leaveTypeRepository,
IFullFeaturedRepository<LeaveAllocation> leaveAllocationRepository,
IGraphRepository<LeaveAllocation> leaveAllocationRepository,
IMapper mapper)
{
this._leaveRequestRepository = leaveRequestRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ namespace HR.LeaveManagement.Application.Features.LeaveRequests.Handlers.Queries
{
public class GetLeaveRequestDetailRequestHandler : IRequestHandler<GetLeaveRequestDetailRequest, LeaveRequestDto>
{
private readonly IFullFeaturedRepository<LeaveRequest> _leaveRequestRepository;
private readonly IGraphRepository<LeaveRequest> _leaveRequestRepository;
private readonly IMapper _mapper;
private readonly IUserService _userService;

public GetLeaveRequestDetailRequestHandler(IFullFeaturedRepository<LeaveRequest> leaveRequestRepository,
public GetLeaveRequestDetailRequestHandler(IGraphRepository<LeaveRequest> leaveRequestRepository,
IMapper mapper,
IUserService userService)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ namespace HR.LeaveManagement.Application.Features.LeaveRequests.Handlers.Queries
{
public class GetLeaveRequestListRequestHandler : IRequestHandler<GetLeaveRequestListRequest, List<LeaveRequestListDto>>
{
private readonly IFullFeaturedRepository<LeaveRequest> _leaveRequestRepository;
private readonly IGraphRepository<LeaveRequest> _leaveRequestRepository;
private readonly IMapper _mapper;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUserService _userService;

public GetLeaveRequestListRequestHandler(IFullFeaturedRepository<LeaveRequest> leaveRequestRepository,
public GetLeaveRequestListRequestHandler(IGraphRepository<LeaveRequest> leaveRequestRepository,
IMapper mapper,
IHttpContextAccessor httpContextAccessor,
IUserService userService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ namespace HR.LeaveManagement.Application.Features.LeaveTypes.Handlers.Commands
public class CreateLeaveTypeCommandHandler : IRequestHandler<CreateLeaveTypeCommand, BaseCommandResponse>
{
private readonly IMapper _mapper;
private readonly IFullFeaturedRepository<LeaveType> _leaveTypeRepository;
public CreateLeaveTypeCommandHandler(IMapper mapper, IFullFeaturedRepository<LeaveType> leaveTypeRepository)
private readonly IGraphRepository<LeaveType> _leaveTypeRepository;
public CreateLeaveTypeCommandHandler(IMapper mapper, IGraphRepository<LeaveType> leaveTypeRepository)
{
_mapper = mapper;
_leaveTypeRepository = leaveTypeRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,23 @@ namespace HR.LeaveManagement.Application.Features.LeaveTypes.Handlers.Commands
public class DeleteLeaveTypeCommandHandler : IRequestHandler<DeleteLeaveTypeCommand>
{
private readonly IMapper _mapper;
private readonly IFullFeaturedRepository<LeaveType> _leaveTypeRepository;
private readonly IGraphRepository<LeaveType> _leaveTypeRepository;

public DeleteLeaveTypeCommandHandler(IMapper mapper, IFullFeaturedRepository<LeaveType> leaveTypeRepository)
public DeleteLeaveTypeCommandHandler(IMapper mapper, IGraphRepository<LeaveType> leaveTypeRepository)
{
_mapper = mapper;
_leaveTypeRepository = leaveTypeRepository;
this._leaveTypeRepository.DataStoreName = "LeaveManagement";
}

public async Task<Unit> Handle(DeleteLeaveTypeCommand request, CancellationToken cancellationToken)
public async Task Handle(DeleteLeaveTypeCommand request, CancellationToken cancellationToken)
{
var leaveType = await _leaveTypeRepository.FindAsync(request.Id);

if (leaveType == null)
throw new NotFoundException(nameof(LeaveType), request.Id);

await _leaveTypeRepository.DeleteAsync(leaveType);

return Unit.Value;
}
}
}
Loading

0 comments on commit e6c7300

Please sign in to comment.