How to map database column to EF model property in a more efficient way than I'm doing now

c# ef-core-2.0 entity-framework entity-framework-core sql-server

Question

I have a nullable varchar(max) column in SQL Server that I'm mapping to a Guid? in EF code-first. However, this property is actually in a base class that many other entities derive from.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Model1>().Property(e => e.Property1).HasConversion(p => p.ToString(), p => (Guid?)Guid.Parse(p));
}

The above line is repeated many times for each table. Is there a way to tell EF that this is a base class property so the mapping can be declared only once?

1
1
11/11/2018 10:11:27 AM

Accepted Answer

Sure it is possible. With the lack of custom conventions, it is achieved with the "typical" modelBuilder.Model.GetEntityTypes() loop. Something like this (just change the base class and the property names):

var entityTypes = modelBuilder.Model.GetEntityTypes()
    .Where(t => t.ClrType.IsSubclassOf(typeof(BaseClass)));

var valueConverter = new ValueConverter<Guid, string>(
    v => v.ToString(), v => (Guid?)Guid.Parse(v));

foreach (var entityType in entityTypes)
    entityType.FindProperty(nameof(BaseClass.Property1)).SetValueConverter(valueConverter);

You may also consider using the EF Core provided out of the box Guid to String converter:

var valueConverter = new GuidToStringConverter();
2
11/11/2018 10:09:25 AM

Popular Answer

Another way to do is it to have a matching base class IEntityTypeConfiguration:

internal class EntityConfiguration<T> : IEntityTypeConfiguration<T> where T : Entity
{
    public virtual void Configure(EntityTypeBuilder<T> builder)
    {
        builder.Property(e => e.Property1).HasConversion(p => p.ToString(), p => (Guid?)Guid.Parse(p));
        // ... Other base-specific config here
    }
}

(Assuming here your base class is called Entity - change as needed).

This works better when you use the pattern of factoring out your entity configurations, so yours might be like this:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfiguration(new Model1EntityConfiguration());
    modelBuilder.ApplyConfiguration(new Model2EntityConfiguration());
    // ...
}

...

internal sealed class Model1EntityConfiguration : EntityConfiguration<Model1>
{
    public override void Configure(EntityTypeBuilder<Model1> builder)
    {
        base.Configure(builder); // <-- here's the key bit
        // ...; e.g.
        builder.Property(c => c.Name).HasMaxLength(80).IsRequired();
    }
}


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow