Reputation: 1380
What's the best way of specifying a decimal precision without using attributes. I just need to set it in one place for all decimal's in my Data.Models. Its tedious specifying attributes for every decimal.
public class Customer
{
public int customerId { get; set; }
[Column(TypeName = "decimal(18,2)")]
public decimal AvailableAmount { get; set; }
}
Upvotes: 28
Views: 27143
Reputation: 18065
with ef core 6+ you can simplify it like
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
base.ConfigureConventions(configurationBuilder);
configurationBuilder.Properties<string>()
//.AreUnicode(false)
//.AreFixedLength()
.HaveMaxLength(256);
}
Upvotes: -1
Reputation: 1532
I realize this has been answered years ago in a few different variations, but one thing I would like to add is the ability to allow for specification on the property using the [Precision()]
attribute for different precisions, with a fall-thru for all decimal
properties on all entities:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Fetch all entity classes that derive from the `BaseEntity`
var entities = typeof(BaseEntity).Assembly.GetTypes()
.Where(t => t.IsSubclassOf(typeof(BaseEntity)) && !t.IsAbstract);
foreach (var entity in entities)
{
// Iterate thru the properties of the entity
foreach (var property in entity.GetProperties())
{
// If decimal or nullable decimal
// and not using the `Precision` attribtue, define the precision
if ((property.PropertyType == typeof(decimal)
|| property.PropertyType == typeof(decimal?))
&& !property.GetCustomAttributes<PrecisionAttribute>().Any())
{
modelBuilder.Entity(entity)
.Property(property.PropertyType, property.Name).HasPrecision(18, 2);
}
}
}
}
Upvotes: 0
Reputation: 2326
Thanks to @Bigabdoul's answer. There are some situations that have been ignored.
For example if you have added special annotation for special fields this code doesn't care and override it. But I have changed code as below to don't modify that fields.
Maybe you use one of these codes for a special property:
1- Use Column(TypeName)
[Column(TypeName = "decimal(18,2)")]
public decimal Quantity { get; set; }
2- Use Precision
[Precision(18, 2)]
public decimal Quantity { get; set; }
3- Use PropertyBuilder.HasPrecision Method
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>().Property(p => p.MyProperty).HasPrecision(18, 2);
}
4- Use PropertyBuilder.HasColumnType method
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyEntity>().Property(p => p.MyProperty).HasColumnType("decimal(18,2)");
}
5- Use IEntityTypeConfiguration Interface
public class MyEntityConfiguration : IEntityTypeConfiguration<MyEntity>
{
public void Configure(EntityTypeBuilder<MyEntity> builder)
{
builder.ToTable("MyEntity");
builder.Property(x => x.MyEntity).HasPrecision(18, 2);
}
}
And then
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly);
// Or use explicitly
//modelBuilder.ApplyConfiguration(new MyEntityConfiguration());
}
All of these situations will be ignored.
But this code care about them and check if there is no related annotation, it will add it to property.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var decimalProps = modelBuilder.Model
.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => (System.Nullable.GetUnderlyingType(p.ClrType) ?? p.ClrType) == typeof(decimal));
foreach (var property in decimalProps)
{
var annotations = property.GetAnnotations();
if (annotations.Count(x => x.Name is "Relational:ColumnType" or "Precision" or "Scale") != 0) continue;
// Or Use this line if you use older version of C#
// if (annotations.Count(x => x.Name == "Relational:ColumnType" || x.Name == "Precision" || x.Name == "Scale") != 0) continue;
property.SetPrecision(18);
property.SetScale(2);
}
}
Upvotes: 10
Reputation: 1
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
var properties = entityType.ClrType.GetProperties().Where(p => p.PropertyType == typeof(decimal));
foreach (var property in properties)
{
modelBuilder.Entity(entityType.Name).Property(property.Name).HasColumnType("decimal(18,2)");
}
}
http://jameschambers.com/2019/06/No-Type-Was-Specified-for-the-Decimal-Column/
Upvotes: 0
Reputation: 1303
Add following to the OnModelCreating
method in the dbcontext:
protected override void OnModelCreating(ModelBuilder builder)
{
foreach (var property in builder.Model.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
{
property.Relational().ColumnType = "decimal(18,2)";
}
}
Upvotes: 23
Reputation: 1751
The Precision attribute can be used instead of hardcoding the decimal database type in C# code.
This:
[Column(TypeName = "decimal(18,2)")]
public decimal Quantity { get; set; }
Can be defined like this:
[Precision(18, 2)]
public decimal Quantity { get; set; }
Tested with EF Core 6.
Upvotes: 10
Reputation: 991
For those who are struggling with the same issue on EntityFrameworkCore 6.0, this will do it:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var decimalProps = modelBuilder.Model
.GetEntityTypes()
.SelectMany(t => t.GetProperties())
.Where(p => (System.Nullable.GetUnderlyingType(p.ClrType) ?? p.ClrType) == typeof(decimal));
foreach (var property in decimalProps)
{
property.SetPrecision(18);
property.SetScale(2);
}
}
Upvotes: 19
Reputation: 390
I experienced this issu using ASP.NET CORE 5. I added the folowing code to the OnModelcreating method in the DbContext.
protected override void OnModelCreating(ModelBuilder modelBuilder)// Crée la migration
{
modelBuilder.Entity<MyEntity>().Property(p => p.Prix).HasColumnType("decimal(18,4)");
}
And all started working fine.
Upvotes: 9