-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Simplify DbContext by extracting aggregate configuration into dedicat…
…ed classes (#676) ### Summary & Motivation Remove the need for centralized configuration in the `DbContext` when defining aggregates in a self-contained system. Previously, the `DbContext` required a `DbSet<T>` property for each aggregate (table) and explicit configuration in `OnModelCreating` for strongly typed IDs and other EF configurations like `.HasOne<T>()`, `.WithMany()`, `.OnDelete()`, `.ToJson()`, etc. Over time, this made the `DbContext` in a self-contained system big and hard to maintain With this change, all entity configurations are moved to dedicated classes implementing `IEntityTypeConfiguration<T>`, keeping each aggregate's configuration within its vertical slice. The `SharedKernelDbContext` now automatically discovers and registers these configurations, eliminating the need for central configuration. Additionally, the `DbContext` now uses a convention-based approach to create tables, leveraging Humanizer for pluralizing table names. This removes the need to define `DbSet<T>` properties explicitly, making the `DbContext` a lightweight class used only in repositories without requiring customization for new aggregates. ### Downstream Projects Extract an `AggregateConfiguration` file for each aggregate, where the content should match the current configuration in `OnModelCreating` in the self-contained system’s `DbContext`. Example: ```csharp namespace PlatformPlatform.AccountManagement.Features.Signups.Domain; public sealed class SignupConfiguration : IEntityTypeConfiguration<Signup> { public void Configure(EntityTypeBuilder<Signup> builder) { builder.MapStronglyTypedUuid<Signup, SignupId>(a => a.Id); builder.MapStronglyTypedNullableId<Signup, TenantId, string>(u => u.TenantId); } } ``` All properties for tables should be removed from DbContext. Any direct usage of these should be replaced by DbSet<T> in the repository. Example: ```csharp // Before: return accountManagementDbContext.Signups.Where(s => ...); // After: return DbSet.Where(s => ...); ``` ### Checklist - [x] I have added tests, or done manual regression tests - [x] I have updated the documentation, if necessary
- Loading branch information
Showing
11 changed files
with
92 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 1 addition & 42 deletions
43
application/account-management/Core/Database/AccountManagementDbContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,8 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
using PlatformPlatform.AccountManagement.Features.Authentication.Domain; | ||
using PlatformPlatform.AccountManagement.Features.Signups.Domain; | ||
using PlatformPlatform.AccountManagement.Features.Tenants.Domain; | ||
using PlatformPlatform.AccountManagement.Features.Users.Domain; | ||
using PlatformPlatform.SharedKernel.Domain; | ||
using PlatformPlatform.SharedKernel.EntityFramework; | ||
using PlatformPlatform.SharedKernel.ExecutionContext; | ||
|
||
namespace PlatformPlatform.AccountManagement.Database; | ||
|
||
public sealed class AccountManagementDbContext(DbContextOptions<AccountManagementDbContext> options, IExecutionContext executionContext) | ||
: SharedKernelDbContext<AccountManagementDbContext>(options, executionContext) | ||
{ | ||
public DbSet<Login> Logins => Set<Login>(); | ||
|
||
public DbSet<Signup> Signups => Set<Signup>(); | ||
|
||
public DbSet<Tenant> Tenants => Set<Tenant>(); | ||
|
||
public DbSet<User> Users => Set<User>(); | ||
|
||
protected override void OnModelCreating(ModelBuilder modelBuilder) | ||
{ | ||
base.OnModelCreating(modelBuilder); | ||
|
||
// Login | ||
modelBuilder.MapStronglyTypedId<Login, LoginId, string>(t => t.Id); | ||
modelBuilder.MapStronglyTypedId<Login, TenantId, string>(u => u.TenantId); | ||
modelBuilder.MapStronglyTypedUuid<Login, UserId>(u => u.UserId); | ||
|
||
// Signup | ||
modelBuilder.MapStronglyTypedUuid<Signup, SignupId>(a => a.Id); | ||
modelBuilder.MapStronglyTypedNullableId<Signup, TenantId, string>(u => u.TenantId); | ||
|
||
// Tenant | ||
modelBuilder.MapStronglyTypedId<Tenant, TenantId, string>(t => t.Id); | ||
|
||
// User | ||
modelBuilder.MapStronglyTypedUuid<User, UserId>(u => u.Id); | ||
modelBuilder.MapStronglyTypedId<User, TenantId, string>(u => u.TenantId); | ||
modelBuilder.Entity<User>() | ||
.OwnsOne(e => e.Avatar, b => b.ToJson()) | ||
.HasOne<Tenant>() | ||
.WithMany() | ||
.HasForeignKey(u => u.TenantId) | ||
.HasPrincipalKey(t => t.Id); | ||
} | ||
} | ||
: SharedKernelDbContext<AccountManagementDbContext>(options, executionContext); |
16 changes: 16 additions & 0 deletions
16
application/account-management/Core/Features/Authentication/Domain/LoginConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||
using PlatformPlatform.SharedKernel.Domain; | ||
using PlatformPlatform.SharedKernel.EntityFramework; | ||
|
||
namespace PlatformPlatform.AccountManagement.Features.Authentication.Domain; | ||
|
||
public sealed class LoginConfiguration : IEntityTypeConfiguration<Login> | ||
{ | ||
public void Configure(EntityTypeBuilder<Login> builder) | ||
{ | ||
builder.MapStronglyTypedId<Login, LoginId, string>(t => t.Id); | ||
builder.MapStronglyTypedId<Login, TenantId, string>(u => u.TenantId); | ||
builder.MapStronglyTypedUuid<Login, UserId>(u => u.UserId); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
application/account-management/Core/Features/Signups/Domain/SignupConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||
using PlatformPlatform.SharedKernel.Domain; | ||
using PlatformPlatform.SharedKernel.EntityFramework; | ||
|
||
namespace PlatformPlatform.AccountManagement.Features.Signups.Domain; | ||
|
||
public sealed class SignupConfiguration : IEntityTypeConfiguration<Signup> | ||
{ | ||
public void Configure(EntityTypeBuilder<Signup> builder) | ||
{ | ||
builder.MapStronglyTypedUuid<Signup, SignupId>(a => a.Id); | ||
builder.MapStronglyTypedNullableId<Signup, TenantId, string>(u => u.TenantId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
application/account-management/Core/Features/Tenants/Domain/TenantConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||
using PlatformPlatform.SharedKernel.Domain; | ||
using PlatformPlatform.SharedKernel.EntityFramework; | ||
|
||
namespace PlatformPlatform.AccountManagement.Features.Tenants.Domain; | ||
|
||
public sealed class TenantConfiguration : IEntityTypeConfiguration<Tenant> | ||
{ | ||
public void Configure(EntityTypeBuilder<Tenant> builder) | ||
{ | ||
builder.MapStronglyTypedId<Tenant, TenantId, string>(t => t.Id); | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
application/account-management/Core/Features/Users/Domain/UserConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.EntityFrameworkCore.Metadata.Builders; | ||
using PlatformPlatform.AccountManagement.Features.Tenants.Domain; | ||
using PlatformPlatform.SharedKernel.Domain; | ||
using PlatformPlatform.SharedKernel.EntityFramework; | ||
|
||
namespace PlatformPlatform.AccountManagement.Features.Users.Domain; | ||
|
||
public sealed class UserConfiguration : IEntityTypeConfiguration<User> | ||
{ | ||
public void Configure(EntityTypeBuilder<User> builder) | ||
{ | ||
builder.MapStronglyTypedUuid<User, UserId>(u => u.Id); | ||
builder.MapStronglyTypedId<User, TenantId, string>(u => u.TenantId); | ||
builder | ||
.OwnsOne(e => e.Avatar, b => b.ToJson()) | ||
.HasOne<Tenant>() | ||
.WithMany() | ||
.HasForeignKey(u => u.TenantId) | ||
.HasPrincipalKey(t => t.Id); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,9 +13,9 @@ public sealed class DatabaseSeeder | |
public DatabaseSeeder(AccountManagementDbContext accountManagementDbContext) | ||
{ | ||
Tenant1 = Tenant.Create(new TenantId("tenant-1"), "[email protected]"); | ||
accountManagementDbContext.Tenants.AddRange(Tenant1); | ||
accountManagementDbContext.Set<Tenant>().AddRange(Tenant1); | ||
User1 = User.Create(Tenant1.Id, "[email protected]", UserRole.Owner, true, null); | ||
accountManagementDbContext.Users.AddRange(User1); | ||
accountManagementDbContext.Set<User>().AddRange(User1); | ||
|
||
accountManagementDbContext.SaveChanges(); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters