C
C#2mo ago
cypherpotato

Generic converter bounding in EF Core

Is there an way to "easily" define converters for all properties which uses an generic type? Currently, I have something like this:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Properties<EntityId<User>>().HaveConversion<EntityIdValueConverter<User>>();
configurationBuilder.Properties<EntityId<Tenant>>().HaveConversion<EntityIdValueConverter<Tenant>>();
}
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Properties<EntityId<User>>().HaveConversion<EntityIdValueConverter<User>>();
configurationBuilder.Properties<EntityId<Tenant>>().HaveConversion<EntityIdValueConverter<Tenant>>();
}
and an ugly static method that gets all properties from entities, map eachs one and applies the converter using reflection and activator.
1 Reply
cypherpotato
cypherpotatoOP2mo ago
currently, i'm using this:
static void ApplyGenericConverter(ModelBuilder modelBuilder, Type commonType, Type converterGenericType, int? maxLength = null)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var properties = entityType.ClrType.GetProperties()
.Where(p => p.PropertyType.IsAssignableTo(commonType));

foreach (var property in properties)
{
var converterType = converterGenericType.MakeGenericType(property.PropertyType.GenericTypeArguments[0]);

var converter = Activator.CreateInstance(converterType);
if (converter is null)
{
throw new Exception("Error creating the dynamic converter object: " + entityType.ClrType.ToString() + " Property: " + property.ToString());
}

var builder = modelBuilder.Entity(entityType.Name).Property(property.Name)
.HasConversion((ValueConverter)converter);

if (maxLength is int ml) builder = builder.HasMaxLength(ml);
}
}
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
ApplyGenericConverter(modelBuilder, typeof(IEntityId), typeof(EntityIdValueConverter<>), maxLength: 26 + 1 + 3);
ApplyGenericConverter(modelBuilder, typeof(IJsonBox), typeof(JsonBoxValueConverter<>));
}
static void ApplyGenericConverter(ModelBuilder modelBuilder, Type commonType, Type converterGenericType, int? maxLength = null)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var properties = entityType.ClrType.GetProperties()
.Where(p => p.PropertyType.IsAssignableTo(commonType));

foreach (var property in properties)
{
var converterType = converterGenericType.MakeGenericType(property.PropertyType.GenericTypeArguments[0]);

var converter = Activator.CreateInstance(converterType);
if (converter is null)
{
throw new Exception("Error creating the dynamic converter object: " + entityType.ClrType.ToString() + " Property: " + property.ToString());
}

var builder = modelBuilder.Entity(entityType.Name).Property(property.Name)
.HasConversion((ValueConverter)converter);

if (maxLength is int ml) builder = builder.HasMaxLength(ml);
}
}
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
ApplyGenericConverter(modelBuilder, typeof(IEntityId), typeof(EntityIdValueConverter<>), maxLength: 26 + 1 + 3);
ApplyGenericConverter(modelBuilder, typeof(IJsonBox), typeof(JsonBoxValueConverter<>));
}
but that doens't seems correct. each entity has an strong typed ID EntityId<TEntity>, and I want to map all of them for all entities. so, what's the better way to create an converter for all EntityId<> without using reflection and activator?
Want results from more Discord servers?
Add your server