diff --git a/application/Directory.Packages.props b/application/Directory.Packages.props
index 23114cb98..f4ea2367b 100644
--- a/application/Directory.Packages.props
+++ b/application/Directory.Packages.props
@@ -21,6 +21,7 @@
+
diff --git a/application/account-management/Core/Database/AccountManagementDbContext.cs b/application/account-management/Core/Database/AccountManagementDbContext.cs
index 129678040..5141ac3c9 100644
--- a/application/account-management/Core/Database/AccountManagementDbContext.cs
+++ b/application/account-management/Core/Database/AccountManagementDbContext.cs
@@ -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 options, IExecutionContext executionContext)
- : SharedKernelDbContext(options, executionContext)
-{
- public DbSet Logins => Set();
-
- public DbSet Signups => Set();
-
- public DbSet Tenants => Set();
-
- public DbSet Users => Set();
-
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- base.OnModelCreating(modelBuilder);
-
- // Login
- modelBuilder.MapStronglyTypedId(t => t.Id);
- modelBuilder.MapStronglyTypedId(u => u.TenantId);
- modelBuilder.MapStronglyTypedUuid(u => u.UserId);
-
- // Signup
- modelBuilder.MapStronglyTypedUuid(a => a.Id);
- modelBuilder.MapStronglyTypedNullableId(u => u.TenantId);
-
- // Tenant
- modelBuilder.MapStronglyTypedId(t => t.Id);
-
- // User
- modelBuilder.MapStronglyTypedUuid(u => u.Id);
- modelBuilder.MapStronglyTypedId(u => u.TenantId);
- modelBuilder.Entity()
- .OwnsOne(e => e.Avatar, b => b.ToJson())
- .HasOne()
- .WithMany()
- .HasForeignKey(u => u.TenantId)
- .HasPrincipalKey(t => t.Id);
- }
-}
+ : SharedKernelDbContext(options, executionContext);
diff --git a/application/account-management/Core/Features/Authentication/Domain/LoginConfiguration.cs b/application/account-management/Core/Features/Authentication/Domain/LoginConfiguration.cs
new file mode 100644
index 000000000..dd6c812e5
--- /dev/null
+++ b/application/account-management/Core/Features/Authentication/Domain/LoginConfiguration.cs
@@ -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
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.MapStronglyTypedId(t => t.Id);
+ builder.MapStronglyTypedId(u => u.TenantId);
+ builder.MapStronglyTypedUuid(u => u.UserId);
+ }
+}
diff --git a/application/account-management/Core/Features/Signups/Domain/SignupConfiguration.cs b/application/account-management/Core/Features/Signups/Domain/SignupConfiguration.cs
new file mode 100644
index 000000000..2599dfbc6
--- /dev/null
+++ b/application/account-management/Core/Features/Signups/Domain/SignupConfiguration.cs
@@ -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
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.MapStronglyTypedUuid(a => a.Id);
+ builder.MapStronglyTypedNullableId(u => u.TenantId);
+ }
+}
diff --git a/application/account-management/Core/Features/Signups/Domain/SignupRepository.cs b/application/account-management/Core/Features/Signups/Domain/SignupRepository.cs
index a44d5d836..9bb2fc4d1 100644
--- a/application/account-management/Core/Features/Signups/Domain/SignupRepository.cs
+++ b/application/account-management/Core/Features/Signups/Domain/SignupRepository.cs
@@ -14,7 +14,7 @@ public sealed class SignupRepository(AccountManagementDbContext accountManagemen
{
public Signup[] GetByEmailOrTenantId(TenantId tenantId, string email)
{
- return accountManagementDbContext.Signups
+ return DbSet
.Where(r => !r.Completed)
.Where(r => r.TenantId == tenantId || r.Email == email.ToLowerInvariant())
.ToArray();
diff --git a/application/account-management/Core/Features/Tenants/Domain/TenantConfiguration.cs b/application/account-management/Core/Features/Tenants/Domain/TenantConfiguration.cs
new file mode 100644
index 000000000..d070fd1cf
--- /dev/null
+++ b/application/account-management/Core/Features/Tenants/Domain/TenantConfiguration.cs
@@ -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
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.MapStronglyTypedId(t => t.Id);
+ }
+}
diff --git a/application/account-management/Core/Features/Users/Domain/UserConfiguration.cs b/application/account-management/Core/Features/Users/Domain/UserConfiguration.cs
new file mode 100644
index 000000000..13d414512
--- /dev/null
+++ b/application/account-management/Core/Features/Users/Domain/UserConfiguration.cs
@@ -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
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.MapStronglyTypedUuid(u => u.Id);
+ builder.MapStronglyTypedId(u => u.TenantId);
+ builder
+ .OwnsOne(e => e.Avatar, b => b.ToJson())
+ .HasOne()
+ .WithMany()
+ .HasForeignKey(u => u.TenantId)
+ .HasPrincipalKey(t => t.Id);
+ }
+}
diff --git a/application/account-management/Tests/DatabaseSeeder.cs b/application/account-management/Tests/DatabaseSeeder.cs
index 372e65aed..617813bf4 100644
--- a/application/account-management/Tests/DatabaseSeeder.cs
+++ b/application/account-management/Tests/DatabaseSeeder.cs
@@ -13,9 +13,9 @@ public sealed class DatabaseSeeder
public DatabaseSeeder(AccountManagementDbContext accountManagementDbContext)
{
Tenant1 = Tenant.Create(new TenantId("tenant-1"), "owner@tenant-1.com");
- accountManagementDbContext.Tenants.AddRange(Tenant1);
+ accountManagementDbContext.Set().AddRange(Tenant1);
User1 = User.Create(Tenant1.Id, "owner@tenant-1.com", UserRole.Owner, true, null);
- accountManagementDbContext.Users.AddRange(User1);
+ accountManagementDbContext.Set().AddRange(User1);
accountManagementDbContext.SaveChanges();
}
diff --git a/application/shared-kernel/SharedKernel/EntityFramework/ModelBuilderExtensions.cs b/application/shared-kernel/SharedKernel/EntityFramework/ModelBuilderExtensions.cs
index 4e56f1dd2..63509037c 100644
--- a/application/shared-kernel/SharedKernel/EntityFramework/ModelBuilderExtensions.cs
+++ b/application/shared-kernel/SharedKernel/EntityFramework/ModelBuilderExtensions.cs
@@ -1,5 +1,6 @@
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using PlatformPlatform.SharedKernel.StronglyTypedIds;
@@ -11,37 +12,34 @@ public static class ModelBuilderExtensions
/// This method is used to tell Entity Framework how to map a strongly typed ID to a SQL column using the
/// underlying type of the strongly-typed ID.
///
- public static void MapStronglyTypedLongId(this ModelBuilder modelBuilder, Expression> expression)
+ public static void MapStronglyTypedLongId(this EntityTypeBuilder builder, Expression> expression)
where T : class where TId : StronglyTypedLongId
{
- modelBuilder
- .Entity()
+ builder
.Property(expression)
.HasConversion(v => v.Value, v => (Activator.CreateInstance(typeof(TId), v) as TId)!);
}
- public static void MapStronglyTypedUuid(this ModelBuilder modelBuilder, Expression> expression)
+ public static void MapStronglyTypedUuid(this EntityTypeBuilder builder, Expression> expression)
where T : class where TId : StronglyTypedUlid
{
- modelBuilder
- .Entity()
+ builder
.Property(expression)
.HasConversion(v => v.Value, v => (Activator.CreateInstance(typeof(TId), v) as TId)!);
}
- public static void MapStronglyTypedId(this ModelBuilder modelBuilder, Expression> expression)
+ public static void MapStronglyTypedId(this EntityTypeBuilder builder, Expression> expression)
where T : class
where TValue : IComparable
where TId : StronglyTypedId
{
- modelBuilder
- .Entity()
+ builder
.Property(expression)
.HasConversion(v => v.Value, v => (Activator.CreateInstance(typeof(TId), v) as TId)!);
}
public static void MapStronglyTypedNullableId(
- this ModelBuilder modelBuilder,
+ this EntityTypeBuilder builder,
Expression> idExpression
)
where T : class
@@ -54,8 +52,7 @@ public static void MapStronglyTypedNullableId(
var idCoalesceExpression =
Expression.Lambda>(Expression.Coalesce(idValueProperty, nullConstant), idParameter);
- modelBuilder
- .Entity()
+ builder
.Property(idExpression)
.HasConversion(idCoalesceExpression!, v => Activator.CreateInstance(typeof(TId), v) as TId);
}
diff --git a/application/shared-kernel/SharedKernel/EntityFramework/SharedKernelDbContext.cs b/application/shared-kernel/SharedKernel/EntityFramework/SharedKernelDbContext.cs
index 3e94414b5..d7892993f 100644
--- a/application/shared-kernel/SharedKernel/EntityFramework/SharedKernelDbContext.cs
+++ b/application/shared-kernel/SharedKernel/EntityFramework/SharedKernelDbContext.cs
@@ -1,4 +1,5 @@
using System.Linq.Expressions;
+using Humanizer;
using Microsoft.EntityFrameworkCore;
using PlatformPlatform.SharedKernel.Domain;
using PlatformPlatform.SharedKernel.ExecutionContext;
@@ -24,6 +25,15 @@ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
+ modelBuilder.ApplyConfigurationsFromAssembly(typeof(TContext).Assembly);
+
+ // Set pluralized table names for all aggregates
+ foreach (var entityType in modelBuilder.Model.GetEntityTypes())
+ {
+ var tableName = entityType.GetTableName()!.Pluralize();
+ entityType.SetTableName(tableName);
+ }
+
// Ensures that all enum properties are stored as strings in the database.
modelBuilder.UseStringForEnums();
diff --git a/application/shared-kernel/SharedKernel/SharedKernel.csproj b/application/shared-kernel/SharedKernel/SharedKernel.csproj
index cf322645c..45a84e53e 100644
--- a/application/shared-kernel/SharedKernel/SharedKernel.csproj
+++ b/application/shared-kernel/SharedKernel/SharedKernel.csproj
@@ -23,6 +23,7 @@
+