Loop/reflect through all properties in all EF Models to set Column Type
The approach mentioned above does not work when I'm working on EFCore 5.0.1 DB-First. The method below on MS document works:
[Column(TypeName = "decimal(18, 4)")]
public decimal Numeric { get; set; }
In EF Core v1.1.0 you can use something like this:
foreach (var pb in modelBuilder.Model
.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?))
.Select(p => modelBuilder.Entity(p.DeclaringEntityType.ClrType).Property(p.Name)))
{
pb.ForSqlServerHasColumnType("decimal(13,4)");
}
Update (EF Core 2.x): Starting from EF Core 2.0, the model is built separately for each database provider, so HasAbcXyz
methods are replaced with common HasXyz
. The updated code (which also skips the explicitly configured properties) looks like this:
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
{
if (property.Relational().ColumnType == null)
property.Relational().ColumnType = "decimal(13,4)";
}
Update (EF Core 3.x): With EF Core 3.0 metadata API changes (Relational()
extensions removed, properties replaced with Get
/ Set
method pair), the code is as follows:
foreach (var property in modelBuilder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
{
if (property.GetColumnType() == null)
property.SetColumnType("decimal(13,4)");
}
Update (Entity Framework Core 6): EF Core 6 includes convention model configuration that can be used to achieve this to all types.
The advantage over looping through entities manually, is that this conventions already ignore certain types (like Ignore()
, or properties that have Converters).
public class SomeDbContext : DbContext
{
protected override void ConfigureConventions(
ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder
.Properties<decimal>()
.HavePrecision(19, 4);
}
}
EF Core 6.0
It's now simple to configure defaults for every decimal
property (or string
, etc.):
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder
.Properties<decimal>()
.HavePrecision(19, 4);
}
More info: pre-convention model configuration