Skip to main content

Generic Entity Configuration

Extensions Methods

EntityFrameworkExtensions.cs
public interface IEntityMappingConfiguration  
{
void Map(ModelBuilder builder);
}

public abstract class EntityMappingConfiguration<T> : IEntityMappingConfiguration<T> where T : class
{
public abstract void Map(EntityTypeBuilder<T> builder);

public void Map(ModelBuilder builder)
{ Map(builder.Entity<T>());
}
}

public interface IEntityMappingConfiguration<T> : IEntityMappingConfiguration where T : class
{
void Map(EntityTypeBuilder<T> builder);
}

public static class ModelBuilderExtensions
{
private static IEnumerable<Type> GetMappingTypes(this Assembly assembly, Type mappingInterface)
{
return assembly.GetTypes().Where(x => !x.IsAbstract && x.GetInterfaces().Any(y => IntrospectionExtensions.GetTypeInfo(y).IsGenericType && y.GetGenericTypeDefinition() == mappingInterface));
}

public static void AddEntityConfigurationsFromAssembly(this ModelBuilder modelBuilder, Assembly assembly)
{
var mappingTypes = assembly.GetMappingTypes(typeof(IEntityMappingConfiguration<>));

foreach (var config in mappingTypes.Select(Activator.CreateInstance).Cast<IEntityMappingConfiguration>())
{
config.Map(modelBuilder);
}
}
}

DbContext Configuration

ApplicationDbContext.cs
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options) : base(options)
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.AddEntityConfigurationsFromAssembly(GetType().Assembly);
}
}

Per-entity Configuration & Customisation

Simple Example

AuditEventEntityConfiguration.cs
public class AuditEventEntityConfiguration : EntityMappingConfiguration<AuditEvent>  
{
public override void Map(EntityTypeBuilder<AuditEvent> builder)
{
builder
.HasKey(p => p.Id);
}
}

More Complex Example

OrganizationEntityConfiguration.cs
public class OrganizationEntityConfiguration : EntityMappingConfiguration<Organization>
{
public override void Map(EntityTypeBuilder<Organization> builder)
{
builder
.HasKey(p => p.Id);

builder
.Property(p => p.Name)
.HasMaxLength(100)
.IsRequired();

builder
.HasIndex(p => p.Name)
.IsUnique();

builder
.OwnsOne(p => p.FeatureFlag);

builder
.Property(b => b.TriggerWords)
.HasConversion(
v => JsonSerializer.Serialize(v, (JsonSerializerOptions) null),
v => JsonSerializer.Deserialize<List<string>>(v, (JsonSerializerOptions) null),
new ValueComparer<List<string>>(
(c1, c2) => c1.SequenceEqual(c2),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
c => c.ToList()))
.HasColumnType("jsonb");
}
}