diff --git a/src/Dfe.SignIn.Core.Interfaces/DataAccess/IUnitOfWork.cs b/src/Dfe.SignIn.Core.Interfaces/DataAccess/IUnitOfWork.cs
deleted file mode 100644
index 1e5daf7e..00000000
--- a/src/Dfe.SignIn.Core.Interfaces/DataAccess/IUnitOfWork.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-namespace Dfe.SignIn.Core.Interfaces.DataAccess;
-
-///
-/// Represents a unit of work that manages database transactions and provides
-/// access to repositories. Ensures that a set of operations either fully succeed
-/// or are rolled back as a single atomic operation.
-///
-public interface IUnitOfWork : IDisposable, IAsyncDisposable
-{
- ///
- /// Returns a queryable source for the specified entity type.
- ///
- ///
- /// The entity type to be queried.
- ///
- ///
- /// An that can be used to query or modify
- /// instances of .
- ///
- IQueryable Repository() where TEntity : class;
-
- ///
- /// Asynchronously adds the specified entity to the current unit of work.
- ///
- ///
- /// The type of the entity being added.
- ///
- /// The entity instance to add.
- /// The cancellation token.
- ///
- /// A task that represents the asynchronous operation.
- ///
- Task AddAsync(TEntity entity, CancellationToken cancellationToken = default) where TEntity : class;
-
- ///
- /// Marks the specified entity for deletion in the current unit of work.
- ///
- ///
- /// The type of the entity being removed.
- ///
- ///
- /// The entity instance to remove.
- ///
- void Remove(TEntity entity) where TEntity : class;
-
- ///
- /// Persists all pending changes to the database.
- ///
- /// An optional cancellation token.
- ///
- /// The number of state entries written to the database.
- ///
- Task SaveChangesAsync(CancellationToken cancellationToken = default);
-
- ///
- /// Begins a new database transaction.
- ///
- /// An optional cancellation token.
- Task BeginTransactionAsync(CancellationToken cancellationToken = default);
-
- ///
- /// Commits the currently active database transaction.
- ///
- /// An optional cancellation token.
- Task CommitTransactionAsync(CancellationToken cancellationToken = default);
-
- ///
- /// Rolls back the currently active database transaction.
- ///
- /// An optional cancellation token.
- Task RollbackTransactionAsync(CancellationToken cancellationToken = default);
-}
-
-///
-/// A unit of work for the Directories database.
-///
-public interface IUnitOfWorkDirectories : IUnitOfWork { }
-
-///
-/// A unit of work for the Organisations database.
-///
-public interface IUnitOfWorkOrganisations : IUnitOfWork { }
-
-///
-/// A unit of work for the Audit database.
-///
-public interface IUnitOfWorkAudit : IUnitOfWork { }
diff --git a/src/Dfe.SignIn.Core.Interfaces/Dfe.SignIn.Core.Interfaces.csproj b/src/Dfe.SignIn.Core.Interfaces/Dfe.SignIn.Core.Interfaces.csproj
index f5265b0b..c9f7cdd8 100644
--- a/src/Dfe.SignIn.Core.Interfaces/Dfe.SignIn.Core.Interfaces.csproj
+++ b/src/Dfe.SignIn.Core.Interfaces/Dfe.SignIn.Core.Interfaces.csproj
@@ -13,4 +13,8 @@
+
+
+
+
diff --git a/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationApiConfigurationUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationApiConfigurationUseCase.cs
index 7cc24e74..e27d0d6b 100644
--- a/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationApiConfigurationUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationApiConfigurationUseCase.cs
@@ -1,8 +1,7 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Applications;
using Dfe.SignIn.Core.Contracts.PublicApi;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Applications;
@@ -11,8 +10,8 @@ namespace Dfe.SignIn.Core.UseCases.Applications;
/// Use case responsible for obtaining the Public API configuration of an application.
///
public sealed class GetApplicationApiConfigurationUseCase(
- IInteractionDispatcher interaction,
- IUnitOfWorkOrganisations uowOrganisations
+ DbOrganisationsContext uowOrganisations,
+ IInteractionDispatcher interaction
) : Interactor
{
///
@@ -22,7 +21,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var serviceEntity = await uowOrganisations.Repository()
+ var serviceEntity = await uowOrganisations.Services
.Select(x => new {
x.ClientId,
x.ApiSecret,
diff --git a/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationByClientIdUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationByClientIdUseCase.cs
index b2d501dc..3909bee2 100644
--- a/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationByClientIdUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationByClientIdUseCase.cs
@@ -1,7 +1,6 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Applications;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Applications;
@@ -9,9 +8,7 @@ namespace Dfe.SignIn.Core.UseCases.Applications;
///
/// Use case responsible for obtaining information about an application.
///
-public sealed class GetApplicationByClientIdUseCase(
- IUnitOfWorkOrganisations uowOrganisations
-) : Interactor
+public sealed class GetApplicationByClientIdUseCase(DbOrganisationsContext uowOrganisations) : Interactor
{
///
public override async Task InvokeAsync(
@@ -20,7 +17,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var serviceEntity = await uowOrganisations.Repository()
+ var serviceEntity = await uowOrganisations.Services
.Select(x => new {
x.Id,
x.ClientId,
diff --git a/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationRolesUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationRolesUseCase.cs
index cb9bb5b4..654e6ebe 100644
--- a/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationRolesUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Applications/GetApplicationRolesUseCase.cs
@@ -1,8 +1,7 @@
using System.Data;
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Applications;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Applications;
@@ -10,9 +9,7 @@ namespace Dfe.SignIn.Core.UseCases.Applications;
///
/// Use case responsible for obtaining information about an application.
///
-public sealed class GetApplicationRolesUseCase(
- IUnitOfWorkOrganisations uowOrganisations
-) : Interactor
+public sealed class GetApplicationRolesUseCase(DbOrganisationsContext uowOrganisations) : Interactor
{
///
public override async Task InvokeAsync(
@@ -21,7 +18,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var roles = await uowOrganisations.Repository()
+ var roles = await uowOrganisations.Roles
.Include(r => r.Parent)
.Where(r => r.ApplicationId == context.Request.ApplicationId)
.OrderBy(r => r.Name)
diff --git a/src/Dfe.SignIn.Core.UseCases/Dfe.SignIn.Core.UseCases.csproj b/src/Dfe.SignIn.Core.UseCases/Dfe.SignIn.Core.UseCases.csproj
index 8685f362..def8bab9 100644
--- a/src/Dfe.SignIn.Core.UseCases/Dfe.SignIn.Core.UseCases.csproj
+++ b/src/Dfe.SignIn.Core.UseCases/Dfe.SignIn.Core.UseCases.csproj
@@ -22,6 +22,7 @@
+
diff --git a/src/Dfe.SignIn.Core.UseCases/Organisations/GetOrganisationByIdUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Organisations/GetOrganisationByIdUseCase.cs
index 43a022e4..4f2375b5 100644
--- a/src/Dfe.SignIn.Core.UseCases/Organisations/GetOrganisationByIdUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Organisations/GetOrganisationByIdUseCase.cs
@@ -1,7 +1,6 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Organisations;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Organisations;
@@ -9,9 +8,7 @@ namespace Dfe.SignIn.Core.UseCases.Organisations;
///
/// Use case for getting information about an organisation.
///
-public sealed class GetOrganisationByIdUseCase(
- IUnitOfWorkOrganisations uowOrganisations
-) : Interactor
+public sealed class GetOrganisationByIdUseCase(DbOrganisationsContext uowOrganisations) : Interactor
{
///
public override async Task InvokeAsync(
@@ -20,7 +17,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var organisationEntity = await uowOrganisations.Repository()
+ var organisationEntity = await uowOrganisations.Organisations
.Where(x => x.Id == context.Request.OrganisationId)
.FirstOrDefaultAsync(cancellationToken)
?? throw OrganisationNotFoundException.FromOrganisationId(context.Request.OrganisationId);
diff --git a/src/Dfe.SignIn.Core.UseCases/Organisations/GetUsersAtOrganisationUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Organisations/GetUsersAtOrganisationUseCase.cs
index 10b87157..e18516d4 100644
--- a/src/Dfe.SignIn.Core.UseCases/Organisations/GetUsersAtOrganisationUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Organisations/GetUsersAtOrganisationUseCase.cs
@@ -2,9 +2,9 @@
using System.Linq.Expressions;
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Organisations;
-using Dfe.SignIn.Core.Entities.Directories;
+
using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Organisations;
@@ -13,9 +13,7 @@ namespace Dfe.SignIn.Core.UseCases.Organisations;
/// Query returns users and their roles for a service and organisation.
///
///
-public sealed class GetUsersAtOrganisationUseCase(
- IUnitOfWorkOrganisations uowOrganisations
-) : Interactor
+public sealed class GetUsersAtOrganisationUseCase(DbOrganisationsContext uowOrganisations) : Interactor
{
///
public override async Task InvokeAsync(
@@ -53,18 +51,18 @@ private IQueryable BuildQuery(
Expression> organisationFilter)
{
var organisations = uowOrganisations
- .Repository()
+ .Organisations
.Where(organisationFilter);
return
- from us in uowOrganisations.Repository()
+ from us in uowOrganisations.UserServices
join o in organisations
on us.OrganisationId equals o.Id
- join u in uowOrganisations.Repository()
+ join u in uowOrganisations.Users
on us.UserId equals u.Sub
- join s in uowOrganisations.Repository()
+ join s in uowOrganisations.Services
on us.ServiceId equals s.Id
- join usr in uowOrganisations.Repository()
+ join usr in uowOrganisations.UserServiceRoles
on new {
oid = us.OrganisationId,
sid = us.ServiceId,
@@ -77,7 +75,7 @@ join usr in uowOrganisations.Repository()
}
into usrGroup
from usr in usrGroup.DefaultIfEmpty()
- join r in uowOrganisations.Repository()
+ join r in uowOrganisations.Roles
on usr.RoleId equals r.Id
into roleGroup
from r in roleGroup.DefaultIfEmpty()
diff --git a/src/Dfe.SignIn.Core.UseCases/SupportTickets/GetApplicationNamesForSupportTicketUseCase.cs b/src/Dfe.SignIn.Core.UseCases/SupportTickets/GetApplicationNamesForSupportTicketUseCase.cs
index 8148aa52..2b2f8e4b 100644
--- a/src/Dfe.SignIn.Core.UseCases/SupportTickets/GetApplicationNamesForSupportTicketUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/SupportTickets/GetApplicationNamesForSupportTicketUseCase.cs
@@ -1,7 +1,6 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.SupportTickets;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.SupportTickets;
@@ -10,9 +9,7 @@ namespace Dfe.SignIn.Core.UseCases.SupportTickets;
/// Use case for getting a list of application names that can be chosen from
/// when raising a support ticket.
///
-public sealed class GetApplicationNamesForSupportTicketUseCase(
- IUnitOfWorkOrganisations unitOfWork
-) : Interactor
+public sealed class GetApplicationNamesForSupportTicketUseCase(DbOrganisationsContext unitOfWork) : Interactor
{
///
public override async Task InvokeAsync(
@@ -21,7 +18,7 @@ public override async Task InvokeAs
{
context.ThrowIfHasValidationErrors();
- var applications = await unitOfWork.Repository()
+ var applications = await unitOfWork.Services
.Where(x => !x.IsChildService && !x.ServiceParams.Any(sp =>
sp.ParamName == "helpHidden" &&
sp.ParamValue == "true"))
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/ChangeJobTitleUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/ChangeJobTitleUseCase.cs
index df52b39c..91505cf6 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/ChangeJobTitleUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/ChangeJobTitleUseCase.cs
@@ -1,8 +1,7 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Audit;
using Dfe.SignIn.Core.Contracts.Users;
-using Dfe.SignIn.Core.Entities.Directories;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -11,7 +10,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// An interactor to change the job title of a user.
///
public sealed class ChangeJobTitleUseCase(
- IUnitOfWorkDirectories unitOfWork,
+ DbDirectoriesContext unitOfWork,
IInteractionDispatcher interaction
) : Interactor
{
@@ -22,7 +21,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var user = await unitOfWork.Repository()
+ var user = await unitOfWork.Users
.Where(x => x.Sub == context.Request.UserId)
.FirstOrDefaultAsync(cancellationToken) ?? throw UserNotFoundException.FromUserId(context.Request.UserId);
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/ChangeNameUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/ChangeNameUseCase.cs
index 4e6d3281..1a99ea05 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/ChangeNameUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/ChangeNameUseCase.cs
@@ -1,8 +1,7 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Audit;
using Dfe.SignIn.Core.Contracts.Users;
-using Dfe.SignIn.Core.Entities.Directories;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -11,7 +10,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// An interactor to change the job title of a user.
///
public sealed class ChangeNameUseCase(
- IUnitOfWorkDirectories unitOfWork,
+ DbDirectoriesContext unitOfWork,
IInteractionDispatcher interaction
) : Interactor
{
@@ -22,7 +21,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var user = await unitOfWork.Repository()
+ var user = await unitOfWork.Users
.Where(x => x.Sub == context.Request.UserId)
.FirstOrDefaultAsync(cancellationToken) ?? throw UserNotFoundException.FromUserId(context.Request.UserId);
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/CreateUserUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/CreateUserUseCase.cs
index c342828c..08402b30 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/CreateUserUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/CreateUserUseCase.cs
@@ -2,7 +2,7 @@
using Dfe.SignIn.Core.Contracts.Search;
using Dfe.SignIn.Core.Contracts.Users;
using Dfe.SignIn.Core.Entities.Directories;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -20,8 +20,8 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// Review login.dfe.directories for implementation details.
///
public sealed class CreateUserUseCase(
+ DbDirectoriesContext unitOfWork,
IInteractionDispatcher interaction,
- IUnitOfWorkDirectories unitOfWork,
TimeProvider timeProvider
) : Interactor
{
@@ -32,7 +32,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var user = await unitOfWork.Repository()
+ var user = await unitOfWork.Users
.Where(x =>
x.Email == context.Request.EmailAddress ||
x.EntraOid == context.Request.EntraUserId)
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/GetOrganisationsAssociatedWithUserUserCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/GetOrganisationsAssociatedWithUserUserCase.cs
index 2c31d649..46e4fa18 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/GetOrganisationsAssociatedWithUserUserCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/GetOrganisationsAssociatedWithUserUserCase.cs
@@ -1,8 +1,7 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Users;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
using Dfe.SignIn.Core.UseCases.Organisations;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -11,7 +10,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// Use case for getting all of the organisations that are associated with a particular user.
///
public sealed class GetOrganisationsAssociatedWithUserUseCase(
- IUnitOfWorkOrganisations unitOfWork
+ DbOrganisationsContext unitOfWork
)
: Interactor
{
@@ -22,7 +21,7 @@ public override async Task InvokeAsy
{
context.ThrowIfHasValidationErrors();
- var organisations = await unitOfWork.Repository()
+ var organisations = await unitOfWork.UserOrganisations
.Where(x => x.UserId == context.Request.UserId)
.Select(x => OrganisationHelpers.OrganisationFromEntity(x.Organisation))
.ToArrayAsync(cancellationToken);
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/GetServiceUsersUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/GetServiceUsersUseCase.cs
index c58a73bc..69fbe808 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/GetServiceUsersUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/GetServiceUsersUseCase.cs
@@ -5,7 +5,7 @@
using Dfe.SignIn.Core.Contracts.Users;
using Dfe.SignIn.Core.Entities.Directories;
using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -14,9 +14,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// Get the service users for a given service (client).
///
///
-public sealed class GetServiceUsersUseCase(
- IUnitOfWorkOrganisations uowOrganisations
-) : Interactor
+public sealed class GetServiceUsersUseCase(DbOrganisationsContext uowOrganisations) : Interactor
{
///
public override async Task InvokeAsync(
@@ -29,7 +27,7 @@ public override async Task InvokeAsync(
var pageSize = context.Request.PageSize;
var pageNumber = context.Request.PageNumber;
- var query = uowOrganisations.Repository()
+ var query = uowOrganisations.UserServices
.AsNoTracking()
.Include(x => x.User)
.Include(x => x.Organisation)
@@ -88,7 +86,7 @@ public override async Task InvokeAsync(
private async Task> GetServiceRolesLookupAsync(
Guid appId, List userIds, CancellationToken ct)
{
- var roles = await uowOrganisations.Repository()
+ var roles = await uowOrganisations.UserServiceRoles
.AsNoTracking()
.Include(x => x.Role)
.Where(x => x.ServiceId == appId)
@@ -109,7 +107,7 @@ public override async Task InvokeAsync(
private async Task> GetOrgRolesLookupAsync(
List userIds, CancellationToken ct)
{
- var orgRoles = await uowOrganisations.Repository()
+ var orgRoles = await uowOrganisations.UserOrganisations
.AsNoTracking()
.Where(x => userIds.Contains(x.UserId))
.Select(x => new { x.UserId, x.OrganisationId, x.RoleId })
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/GetUserOrganisationIdentifiersUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/GetUserOrganisationIdentifiersUseCase.cs
index e9e8fdef..a8de41bc 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/GetUserOrganisationIdentifiersUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/GetUserOrganisationIdentifiersUseCase.cs
@@ -1,7 +1,6 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Users;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -12,7 +11,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// legacy system integration.
///
public sealed class GetUserOrganisationIdentifiersUseCase(
- IUnitOfWorkOrganisations uowOrganisations
+ DbOrganisationsContext unitOfWork
) : Interactor
{
///
@@ -22,8 +21,8 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var userOrganisation = await uowOrganisations
- .Repository()
+ var userOrganisation = await unitOfWork
+ .UserOrganisations
.Where(x => x.UserId == context.Request.UserId
&& x.OrganisationId == context.Request.OrganisationId)
.FirstOrDefaultAsync(cancellationToken);
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/GetUserProfileUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/GetUserProfileUseCase.cs
index a29ef45c..0c35e265 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/GetUserProfileUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/GetUserProfileUseCase.cs
@@ -1,7 +1,6 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Users;
-using Dfe.SignIn.Core.Entities.Directories;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -10,7 +9,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// Use case for getting the profile of a user.
///
public sealed class GetUserProfileUseCase(
- IUnitOfWorkDirectories unitOfWork
+ DbDirectoriesContext unitOfWork
) : Interactor
{
///
@@ -20,7 +19,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var user = await unitOfWork.Repository()
+ var user = await unitOfWork.Users
.Where(x => x.Sub == context.Request.UserId)
.FirstOrDefaultAsync(cancellationToken)
?? throw UserNotFoundException.FromUserId(context.Request.UserId);
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/GetUserServiceAccessDetailsUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/GetUserServiceAccessDetailsUseCase.cs
index 9e99e701..19348d68 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/GetUserServiceAccessDetailsUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/GetUserServiceAccessDetailsUseCase.cs
@@ -2,8 +2,7 @@
using Dfe.SignIn.Core.Contracts.Access;
using Dfe.SignIn.Core.Contracts.Organisations;
using Dfe.SignIn.Core.Contracts.Users;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -25,8 +24,8 @@ namespace Dfe.SignIn.Core.UseCases.Users;
///
///
public sealed class GetUserServiceAccessDetailsUseCase(
- IInteractionDispatcher interaction,
- IUnitOfWorkOrganisations uowOrganisations
+ DbOrganisationsContext uowOrganisations,
+ IInteractionDispatcher interaction
) : Interactor
{
///
@@ -85,7 +84,7 @@ public override async Task InvokeAsync(
private async Task GetUserService(Guid userId, Guid serviceId, Guid organisationId)
{
- var userService = await uowOrganisations.Repository()
+ var userService = await uowOrganisations.UserServices
.AsNoTracking()
.Where(x => x.ServiceId == serviceId)
.Where(x => x.UserId == userId)
@@ -96,7 +95,7 @@ private async Task GetUserService(Guid userId, Gui
return new GetUserServiceAccessResponse { Access = null };
}
- var roles = await uowOrganisations.Repository()
+ var roles = await uowOrganisations.UserServiceRoles
.AsNoTracking()
.Include(x => x.Role)
.Where(x => x.UserId == userId)
@@ -104,7 +103,7 @@ private async Task GetUserService(Guid userId, Gui
.Where(x => x.OrganisationId == organisationId)
.ToListAsync();
- var identifiers = await uowOrganisations.Repository()
+ var identifiers = await uowOrganisations.UserServiceIdentifiers
.AsNoTracking()
.Where(x => x.UserId == userId)
.Where(x => x.ServiceId == serviceId)
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/GetUserStatusUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/GetUserStatusUseCase.cs
index d7ceed84..1243c903 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/GetUserStatusUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/GetUserStatusUseCase.cs
@@ -2,7 +2,7 @@
using Dfe.SignIn.Base.Framework.Internal;
using Dfe.SignIn.Core.Contracts.Users;
using Dfe.SignIn.Core.Entities.Directories;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -11,7 +11,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// An interactor to determine if a user exists and retrieve their account status.
///
public sealed class GetUserStatusUseCase(
- IUnitOfWorkDirectories unitOfWork
+ DbDirectoriesContext unitOfWork
) : Interactor
{
///
@@ -21,7 +21,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var queryBuilder = unitOfWork.Repository();
+ IQueryable queryBuilder = unitOfWork.Users;
queryBuilder = context.Request.EntraUserId.HasValue
? queryBuilder.Where(x => x.EntraOid == context.Request.EntraUserId.Value)
: queryBuilder.Where(x => x.Email == context.Request.EmailAddress);
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/IsOrganisationApproverUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/IsOrganisationApproverUseCase.cs
index 8e3755b6..8f8ad6d4 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/IsOrganisationApproverUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/IsOrganisationApproverUseCase.cs
@@ -1,8 +1,7 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Organisations;
using Dfe.SignIn.Core.Contracts.Users;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -10,9 +9,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
///
/// Use case for checking if a user is an approver for any of their associated organisations.
///
-public sealed class IsOrganisationApproverUseCase(
- IUnitOfWorkOrganisations unitOfWork
-)
+public sealed class IsOrganisationApproverUseCase(DbOrganisationsContext unitOfWork)
: Interactor
{
///
@@ -22,7 +19,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var isApprover = await unitOfWork.Repository()
+ var isApprover = await unitOfWork.UserOrganisations
.Where(x => x.UserId == context.Request.UserId)
.AnyAsync(x => x.RoleId == OrganisationRoles.Approver.Id, cancellationToken);
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/LinkEntraUserToDsiUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/LinkEntraUserToDsiUseCase.cs
index 7b76721b..36b7316b 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/LinkEntraUserToDsiUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/LinkEntraUserToDsiUseCase.cs
@@ -1,8 +1,7 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Audit;
using Dfe.SignIn.Core.Contracts.Users;
-using Dfe.SignIn.Core.Entities.Directories;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -11,7 +10,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// Use case for linking an Entra user to a DfE Sign-in user.
///
public sealed class LinkEntraUserToDsiUseCase(
- IUnitOfWorkDirectories unitOfWork,
+ DbDirectoriesContext unitOfWork,
IInteractionDispatcher interaction,
TimeProvider timeProvider
) : Interactor
@@ -23,7 +22,7 @@ public override async Task InvokeAsync(
{
context.ThrowIfHasValidationErrors();
- var user = await unitOfWork.Repository()
+ var user = await unitOfWork.Users
.Where(x => x.Sub == context.Request.DsiUserId)
.SingleOrDefaultAsync(cancellationToken: cancellationToken)
?? throw UserNotFoundException.FromUserId(context.Request.DsiUserId);
@@ -34,8 +33,7 @@ public override async Task InvokeAsync(
user.Sub, userEntraOid, context.Request.EntraUserId);
}
- var existingEntraUser = await unitOfWork
- .Repository()
+ var existingEntraUser = await unitOfWork.Users
.Where(x => x.EntraOid == context.Request.EntraUserId)
.Select(x => new { x.Sub })
.FirstOrDefaultAsync(cancellationToken);
diff --git a/src/Dfe.SignIn.Core.UseCases/Users/PendingApprovalCountUseCase.cs b/src/Dfe.SignIn.Core.UseCases/Users/PendingApprovalCountUseCase.cs
index dbe8a5cb..846f5ab2 100644
--- a/src/Dfe.SignIn.Core.UseCases/Users/PendingApprovalCountUseCase.cs
+++ b/src/Dfe.SignIn.Core.UseCases/Users/PendingApprovalCountUseCase.cs
@@ -1,8 +1,7 @@
using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Organisations;
using Dfe.SignIn.Core.Contracts.Users;
-using Dfe.SignIn.Core.Entities.Organisations;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
+using Dfe.SignIn.Gateways.EntityFramework;
using Microsoft.EntityFrameworkCore;
namespace Dfe.SignIn.Core.UseCases.Users;
@@ -12,7 +11,7 @@ namespace Dfe.SignIn.Core.UseCases.Users;
/// services for a approval user
///
///
-public sealed class PendingApprovalCountUseCase(IUnitOfWorkOrganisations unitOfWork) : Interactor
+public sealed class PendingApprovalCountUseCase(DbOrganisationsContext unitOfWork) : Interactor
{
///
/// Calculates the number of outstanding approvals that the Approval user for the given
@@ -25,15 +24,15 @@ public sealed class PendingApprovalCountUseCase(IUnitOfWorkOrganisations unitOfW
///
public override async Task InvokeAsync(InteractionContext context, CancellationToken cancellationToken = default)
{
- var orgIds = await unitOfWork.Repository().Include(x => x.Organisation)
+ var orgIds = await unitOfWork.UserOrganisations.Include(x => x.Organisation)
.Where(x => x.UserId == context.Request.UserId && x.RoleId == OrganisationRoles.Approver.Id)
.Select(x => x.OrganisationId)
.ToListAsync(cancellationToken);
- var pendingServiceNotificationCount = await unitOfWork.Repository()
+ var pendingServiceNotificationCount = await unitOfWork.UserServiceRequests
.CountAsync(x => orgIds.Contains(x.OrganisationId) && !x.ActionedAt.HasValue, cancellationToken);
- var pendingOrganisationNotificationCount = await unitOfWork.Repository()
+ var pendingOrganisationNotificationCount = await unitOfWork.UserOrganisationRequests
.CountAsync(x => orgIds.Contains(x.OrganisationId) && !x.ActionedAt.HasValue, cancellationToken);
var pendingCount = pendingServiceNotificationCount + pendingOrganisationNotificationCount;
diff --git a/src/Dfe.SignIn.Gateways.EntityFramework/Configuration/UnitOfWorkEntityFrameworkExtensions.cs b/src/Dfe.SignIn.Gateways.EntityFramework/Configuration/UnitOfWorkEntityFrameworkExtensions.cs
index 8b4d90c9..61ea92e5 100644
--- a/src/Dfe.SignIn.Gateways.EntityFramework/Configuration/UnitOfWorkEntityFrameworkExtensions.cs
+++ b/src/Dfe.SignIn.Gateways.EntityFramework/Configuration/UnitOfWorkEntityFrameworkExtensions.cs
@@ -1,6 +1,5 @@
using Dfe.SignIn.Base.Framework;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
@@ -42,24 +41,22 @@ public static IServiceCollection AddUnitOfWorkEntityFrameworkServices(
if (addDirectoriesUnitOfWork || addOrganisationsUnitOfWork || addAuditUnitOfWork) {
services.TryAddSingleton(TimeProvider.System);
- services.AddScoped();
- services.Decorate();
services.AddScoped();
}
- AddUnitOfWork(
+ AddUnitOfWork(
services,
section,
"Directories",
addDirectoriesUnitOfWork);
- AddUnitOfWork(
+ AddUnitOfWork(
services,
section,
"Organisations",
addOrganisationsUnitOfWork);
- AddUnitOfWork(
+ AddUnitOfWork(
services,
section,
"Audit",
@@ -74,13 +71,6 @@ public static IServiceCollection AddUnitOfWorkEntityFrameworkServices(
/// with a SQL Server connection string derived from configuration and attaches a
/// to automatically manage CreatedAt and UpdatedAt timestamps.
///
- ///
- /// The interface type representing the unit of work contract.
- ///
- ///
- /// The concrete implementation type of the unit of work. Must inherit from
- /// and implement .
- ///
///
/// The type of associated with this unit of work.
///
@@ -104,14 +94,12 @@ public static IServiceCollection AddUnitOfWorkEntityFrameworkServices(
/// (Host, Name, Username, Password)
/// is missing for the specified .
///
- private static void AddUnitOfWork(
+ private static void AddUnitOfWork(
IServiceCollection services,
IConfiguration section,
string configKey,
bool register)
where TDbContext : DbContext
- where TUnitOfWorkConcrete : EntityFrameworkUnitOfWork, TUnitOfWorkContract
- where TUnitOfWorkContract : class, IUnitOfWork
{
if (!register) {
return;
@@ -143,6 +131,5 @@ private static void AddUnitOfWork();
}
}
diff --git a/src/Dfe.SignIn.Gateways.EntityFramework/EntityFrameworkUnitOfWork.cs b/src/Dfe.SignIn.Gateways.EntityFramework/EntityFrameworkUnitOfWork.cs
deleted file mode 100644
index 0adbd242..00000000
--- a/src/Dfe.SignIn.Gateways.EntityFramework/EntityFrameworkUnitOfWork.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-using Dfe.SignIn.Core.Interfaces.DataAccess;
-using Microsoft.EntityFrameworkCore;
-
-namespace Dfe.SignIn.Gateways.EntityFramework;
-
-///
-/// Implements the pattern using Entity Framework Core.
-/// Manages a shared instance and provides access to typed repositories.
-///
-public abstract class EntityFrameworkUnitOfWork : IUnitOfWork
-{
- private readonly DbContext dbContext;
- private readonly IEntityFrameworkTransactionContext transactionContext;
-
- ///
- /// Creates a new using the provided .
- ///
- /// The Entity Framework database context to use.
- /// The Entity Framework core transaction context.
- protected EntityFrameworkUnitOfWork(DbContext dbContext, IEntityFrameworkTransactionContext transactionContext)
- {
- this.dbContext = dbContext;
- this.transactionContext = transactionContext;
- }
-
- ///
- /// Returns an representing the underlying
- /// Entity Framework Core for the specified entity type.
- ///
- ///
- /// The entity type for which the queryable repository is requested.
- ///
- ///
- /// An that can be used to query and modify
- /// entities of type .
- /// Changes made to tracked entities are persisted when the unit of work
- /// is committed.
- ///
- public IQueryable Repository() where TEntity : class
- {
- return this.dbContext.Set();
- }
-
- ///
- ///
- /// This method queues an insert operation by adding the entity to the DbContext.
- /// No database interaction occurs until is called.
- ///
- public async Task AddAsync(TEntity entity, CancellationToken cancellationToken = default) where TEntity : class
- {
- await this.dbContext.Set().AddAsync(entity, cancellationToken);
- }
-
- ///
- ///
- /// This method queues a delete operation by marking the entity as deleted in the DbContext.
- /// No database interaction occurs until is called.
- ///
- public void Remove(TEntity entity) where TEntity : class
- {
- this.dbContext.Set().Remove(entity);
- }
-
- ///
- public Task SaveChangesAsync(CancellationToken cancellationToken = default)
- {
- return this.dbContext.SaveChangesAsync(cancellationToken);
- }
-
- ///
- public async Task BeginTransactionAsync(CancellationToken cancellationToken = default)
- {
- this.transactionContext.InsideTransaction = true;
- await this.dbContext.Database.BeginTransactionAsync(cancellationToken);
- }
-
- ///
- public Task CommitTransactionAsync(CancellationToken cancellationToken = default)
- {
- this.transactionContext.InsideTransaction = false;
- return this.dbContext.Database.CurrentTransaction?.CommitAsync(cancellationToken) ?? Task.CompletedTask;
- }
-
- ///
- public Task RollbackTransactionAsync(CancellationToken cancellationToken = default)
- {
- this.transactionContext.InsideTransaction = false;
- return this.dbContext.Database.CurrentTransaction?.RollbackAsync(cancellationToken) ?? Task.CompletedTask;
- }
-
- ///
- public void Dispose()
- {
- this.Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ///
- /// Core dispose logic for EF Core resources.
- ///
- protected virtual void Dispose(bool disposing)
- {
- if (disposing) {
- this.dbContext?.Dispose();
- }
- }
-
- ///
- public async ValueTask DisposeAsync()
- {
- await this.DisposeAsyncCore();
- GC.SuppressFinalize(this);
- }
-
- ///
- /// Core async dispose logic for EF Core resources.
- ///
- protected virtual async ValueTask DisposeAsyncCore()
- {
- if (this.dbContext != null) {
- await this.dbContext.DisposeAsync();
- }
- }
-}
diff --git a/src/Dfe.SignIn.Gateways.EntityFramework/IEntityFrameworkTransactionContext.cs b/src/Dfe.SignIn.Gateways.EntityFramework/IEntityFrameworkTransactionContext.cs
deleted file mode 100644
index a293b6a6..00000000
--- a/src/Dfe.SignIn.Gateways.EntityFramework/IEntityFrameworkTransactionContext.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-
-namespace Dfe.SignIn.Gateways.EntityFramework;
-
-///
-/// Defines a context for tracking transaction state in Entity Framework operations.
-///
-public interface IEntityFrameworkTransactionContext
-{
- ///
- /// Indicates whether the current context is inside a transaction.
- ///
- bool InsideTransaction { get; set; }
-}
-
-///
-/// Implementation of
-/// that internally tracks nested transaction starts using a counter.
-///
-public sealed class EntityFrameworkTransactionContext : IEntityFrameworkTransactionContext
-{
- private int counter = 0;
-
- ///
- public bool InsideTransaction {
- get => this.counter > 0;
- set => this.counter = Math.Max(0, this.counter + (value ? 1 : -1));
- }
-}
diff --git a/src/Dfe.SignIn.Gateways.EntityFramework/ProtectTransactionInteractionDispatcher.cs b/src/Dfe.SignIn.Gateways.EntityFramework/ProtectTransactionInteractionDispatcher.cs
deleted file mode 100644
index 994a5a35..00000000
--- a/src/Dfe.SignIn.Gateways.EntityFramework/ProtectTransactionInteractionDispatcher.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using Dfe.SignIn.Base.Framework;
-
-namespace Dfe.SignIn.Gateways.EntityFramework;
-
-///
-/// An interaction dispatcher that checks whether the current
-/// is inside a transaction, and throws an exception if so. This prevents nested Entity Framework Core
-/// transactions, which are not supported.
-///
-public sealed class ProtectTransactionInteractionDispatcher(
- IInteractionDispatcher inner,
- IEntityFrameworkTransactionContext transactionContext
-) : IInteractionDispatcher
-{
- ///
- public InteractionTask DispatchAsync(InteractionContext context) where TRequest : class
- {
- if (transactionContext.InsideTransaction) {
- throw new InvalidOperationException("Cannot dispatch interaction within the context of a transaction.");
- }
- return inner.DispatchAsync(context);
- }
-}
diff --git a/src/Dfe.SignIn.Gateways.EntityFramework/UnitOfWorkAudit.cs b/src/Dfe.SignIn.Gateways.EntityFramework/UnitOfWorkAudit.cs
deleted file mode 100644
index c044f9d7..00000000
--- a/src/Dfe.SignIn.Gateways.EntityFramework/UnitOfWorkAudit.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
-
-namespace Dfe.SignIn.Gateways.EntityFramework;
-
-///
-/// Represents a Unit of Work specifically for the .
-/// Inherits from to provide repository access and transaction
-/// management for the audit database.
-///
-///
-/// This class implements as a marker interface
-/// to allow dependency injection to distinguish it from other UnitOfWork implementations.
-/// It is a thin wrapper around and does not add
-/// additional logic.
-///
-[ExcludeFromCodeCoverage]
-public sealed class UnitOfWorkAudit : EntityFrameworkUnitOfWork, IUnitOfWorkAudit
-{
- ///
- /// Initializes a new instance of the class
- /// using the specified .
- ///
- ///
- /// The instance used to perform database operations.
- ///
- ///
- /// The Entity Framework core transaction context.
- ///
- public UnitOfWorkAudit(DbAuditContext db, IEntityFrameworkTransactionContext transactionContext) : base(db, transactionContext) { }
-}
diff --git a/src/Dfe.SignIn.Gateways.EntityFramework/UnitOfWorkDirectories.cs b/src/Dfe.SignIn.Gateways.EntityFramework/UnitOfWorkDirectories.cs
deleted file mode 100644
index e04c8f6e..00000000
--- a/src/Dfe.SignIn.Gateways.EntityFramework/UnitOfWorkDirectories.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
-
-namespace Dfe.SignIn.Gateways.EntityFramework;
-
-///
-/// Represents a Unit of Work specifically for the .
-/// Inherits from to provide repository access and transaction
-/// management for the directories database.
-///
-///
-/// This class implements as a marker interface
-/// to allow dependency injection to distinguish it from other UnitOfWork implementations.
-/// It is a thin wrapper around and does not add
-/// additional logic.
-///
-[ExcludeFromCodeCoverage]
-public sealed class UnitOfWorkDirectories : EntityFrameworkUnitOfWork, IUnitOfWorkDirectories
-{
- ///
- /// Initializes a new instance of the class
- /// using the specified .
- ///
- ///
- /// The instance used to perform database operations.
- ///
- ///
- /// The Entity Framework core transaction context.
- ///
- public UnitOfWorkDirectories(DbDirectoriesContext db, IEntityFrameworkTransactionContext transactionContext) : base(db, transactionContext) { }
-}
diff --git a/src/Dfe.SignIn.Gateways.EntityFramework/UnitOfWorkOrganisations.cs b/src/Dfe.SignIn.Gateways.EntityFramework/UnitOfWorkOrganisations.cs
deleted file mode 100644
index 47bfb07c..00000000
--- a/src/Dfe.SignIn.Gateways.EntityFramework/UnitOfWorkOrganisations.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System.Diagnostics.CodeAnalysis;
-using Dfe.SignIn.Core.Interfaces.DataAccess;
-
-namespace Dfe.SignIn.Gateways.EntityFramework;
-
-///
-/// Represents a Unit of Work specifically for the .
-/// Inherits from to provide repository access and transaction
-/// management for the organisations database.
-///
-///
-/// This class implements as a marker interface
-/// to allow dependency injection to distinguish it from other UnitOfWork implementations.
-/// It is a thin wrapper around and does not add
-/// additional logic.
-///
-[ExcludeFromCodeCoverage]
-public sealed class UnitOfWorkOrganisations : EntityFrameworkUnitOfWork, IUnitOfWorkOrganisations
-{
- ///
- /// Initializes a new instance of the class
- /// using the specified .
- ///
- ///
- /// The instance used to perform database operations.
- ///
- ///
- /// The Entity Framework core transaction context.
- ///
- public UnitOfWorkOrganisations(DbOrganisationsContext db, IEntityFrameworkTransactionContext transactionContext) : base(db, transactionContext) { }
-}
diff --git a/tests/Dfe.SignIn.Core.UseCases.UnitTests/Applications/GetApplicationApiConfigurationUseCaseTests.cs b/tests/Dfe.SignIn.Core.UseCases.UnitTests/Applications/GetApplicationApiConfigurationUseCaseTests.cs
index 7e94afd1..fe8a4303 100644
--- a/tests/Dfe.SignIn.Core.UseCases.UnitTests/Applications/GetApplicationApiConfigurationUseCaseTests.cs
+++ b/tests/Dfe.SignIn.Core.UseCases.UnitTests/Applications/GetApplicationApiConfigurationUseCaseTests.cs
@@ -1,7 +1,11 @@
+using Dfe.SignIn.Base.Framework;
using Dfe.SignIn.Core.Contracts.Applications;
using Dfe.SignIn.Core.Contracts.PublicApi;
using Dfe.SignIn.Core.Entities.Organisations;
using Dfe.SignIn.Core.UseCases.Applications;
+using Dfe.SignIn.Gateways.EntityFramework;
+using Microsoft.EntityFrameworkCore;
+using Moq;
using Moq.AutoMock;
namespace Dfe.SignIn.Core.UseCases.UnitTests.Applications;
@@ -12,15 +16,27 @@ public sealed class GetApplicationApiConfigurationUseCaseTests
[TestMethod]
public Task Throws_WhenRequestIsInvalid()
{
+ var autoMocker = new AutoMocker();
+ var options = new DbContextOptionsBuilder()
+ .UseInMemoryDatabase(Guid.NewGuid().ToString())
+ .Options;
+
+ var orgCtx = new DbOrganisationsContext(options);
+ autoMocker.Use(orgCtx);
+
return InteractionAssert.ThrowsWhenRequestIsInvalid<
GetApplicationApiConfigurationRequest,
GetApplicationApiConfigurationUseCase
- >();
+ >(autoMocker);
}
- private static async Task SetupFakeDatabaseAsync(AutoMocker autoMocker)
+ private static async Task SetupFakeDatabaseAsync()
{
- var ctx = autoMocker.UseInMemoryOrganisationsDb();
+ var options = new DbContextOptionsBuilder()
+ .UseInMemoryDatabase(Guid.NewGuid().ToString())
+ .Options;
+
+ var ctx = new DbOrganisationsContext(options);
ctx.Services.Add(new ServiceEntity {
Id = Guid.Parse("b03e0aa5-f2a9-4926-8be0-9b996f97790d"),
@@ -31,14 +47,15 @@ private static async Task SetupFakeDatabaseAsync(AutoMocker autoMocker)
});
await ctx.SaveChangesAsync();
+
+ return ctx;
}
[TestMethod]
public async Task Throws_WhenApplicationNotFound()
{
- var autoMocker = new AutoMocker();
- await SetupFakeDatabaseAsync(autoMocker);
- var interactor = autoMocker.CreateInstance();
+ var orgCtx = await SetupFakeDatabaseAsync();
+ GetApplicationApiConfigurationUseCase interactor = new(orgCtx, Mock.Of());
string nonExistentClientId = "non-existent";
@@ -55,7 +72,9 @@ public async Task Throws_WhenApplicationNotFound()
public async Task ReturnsApiConfiguration()
{
var autoMocker = new AutoMocker();
- await SetupFakeDatabaseAsync(autoMocker);
+ var orgCtx = await SetupFakeDatabaseAsync();
+
+ autoMocker.Use(orgCtx); // register DbContext
autoMocker.MockResponse(
new DecryptApiSecretRequest {
@@ -66,7 +85,8 @@ public async Task ReturnsApiConfiguration()
}
);
- var interactor = autoMocker.CreateInstance();
+ var interactor = autoMocker
+ .CreateInstance();
var response = await interactor.InvokeAsync(
new GetApplicationApiConfigurationRequest {
diff --git a/tests/Dfe.SignIn.Core.UseCases.UnitTests/Applications/GetApplicationByClientIdUseCaseTests.cs b/tests/Dfe.SignIn.Core.UseCases.UnitTests/Applications/GetApplicationByClientIdUseCaseTests.cs
index 80c1f77f..cc2cee44 100644
--- a/tests/Dfe.SignIn.Core.UseCases.UnitTests/Applications/GetApplicationByClientIdUseCaseTests.cs
+++ b/tests/Dfe.SignIn.Core.UseCases.UnitTests/Applications/GetApplicationByClientIdUseCaseTests.cs
@@ -1,6 +1,8 @@
using Dfe.SignIn.Core.Contracts.Applications;
using Dfe.SignIn.Core.Entities.Organisations;
using Dfe.SignIn.Core.UseCases.Applications;
+using Dfe.SignIn.Gateways.EntityFramework;
+using Microsoft.EntityFrameworkCore;
using Moq.AutoMock;
namespace Dfe.SignIn.Core.UseCases.UnitTests.Applications;
@@ -11,15 +13,27 @@ public sealed class GetApplicationByClientIdUseCaseTests
[TestMethod]
public Task Throws_WhenRequestIsInvalid()
{
+ var autoMocker = new AutoMocker();
+ var options = new DbContextOptionsBuilder()
+ .UseInMemoryDatabase(Guid.NewGuid().ToString())
+ .Options;
+
+ var orgCtx = new DbOrganisationsContext(options);
+ autoMocker.Use(orgCtx);
+
return InteractionAssert.ThrowsWhenRequestIsInvalid<
GetApplicationByClientIdRequest,
GetApplicationByClientIdUseCase
- >();
+ >(autoMocker);
}
- private static async Task SetupFakeDatabaseAsync(AutoMocker autoMocker)
+ private static async Task SetupFakeDatabaseAsync()
{
- var ctx = autoMocker.UseInMemoryOrganisationsDb();
+ var options = new DbContextOptionsBuilder()
+ .UseInMemoryDatabase(Guid.NewGuid().ToString())
+ .Options;
+
+ var ctx = new DbOrganisationsContext(options);
ctx.Services.Add(new ServiceEntity {
Id = Guid.Parse("01e876a1-a06d-4945-bbe0-599a3d73dd11"),
@@ -58,14 +72,15 @@ private static async Task SetupFakeDatabaseAsync(AutoMocker autoMocker)
});
await ctx.SaveChangesAsync();
+
+ return ctx;
}
[TestMethod]
public async Task Throws_WhenApplicationNotFound()
{
- var autoMocker = new AutoMocker();
- await SetupFakeDatabaseAsync(autoMocker);
- var interactor = autoMocker.CreateInstance();
+ var orgCtx = await SetupFakeDatabaseAsync();
+ GetApplicationByClientIdUseCase interactor = new(orgCtx);
string nonExistentClientId = "non-existent";
@@ -131,10 +146,8 @@ public static IEnumerable