My Model:
public class Product { ... public decimal Fineness { get; set; } ... }
Seeding the Database:
new List<Product> { new Product { ..., Fineness = 0.757M, ... }, new Product { ..., Fineness = 0.674M, ... }, new Product { ..., Fineness = 0.475M, ... } }.ForEach(p => context.Products.Add(p));
Querying the Database to test seeding:
var products = db.Products.ToList(); foreach (var p in products) { S.D.Debug.WriteLine("ProductList: {0}, {1}", p.Name, p.Fineness); }
Console Output:
ProductList: Test Product, 0.75 ProductList: Test Product, 0.67 ProductList: Test Product, 0.47
Am I doing something really silly or something??? Everything is being truncated to 2 decimal places.
Solution - Thanks to Patrick:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Product>().Property(x => x.Fineness).HasPrecision(10, 5); }
So you have your standard entity models defined, here is product with id and decimal, along with anything else you require etc.
public class Product { public int Id { get; set; } public decimal Fineness { get; set; } }
So I've defined an initlizer, in which case the database will drop and re-create any seeded information I've provided, each time I run and execute my application, this will be called.
public class Initializer : DropCreateDatabaseAlways<Context> { protected override void Seed(Context context) { // note how I am specifying it here as 4 digits after the decimal point // and for the second one, 3 digits // this is where EF precision must be configured so you can expect // the values you tell EF to save to the db context.Products.Add(new Product() {Id = 1, Fineness = 145.2442m}); context.Products.Add(new Product() {Id = 2, Fineness = 12.341m}); } } public class Context : DbContext { public IDbSet<Product> Products { get; set; } public Context() { // I always explicitly define how my EF should run, but this is not needed for the answer I am providing you Configuration.AutoDetectChangesEnabled = true; Configuration.ProxyCreationEnabled = true; Configuration.LazyLoadingEnabled = true; Configuration.ValidateOnSaveEnabled = true; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // so here, I am override the model configuration which is what // EF can use in order to set-up the behaviour of how everything // is configured in the database, from associations between // multiple entities and property validation, Null-able, Precision, required fields etc modelBuilder.Configurations.Add(new ProductConfiguration()); } } public class ProductConfiguration : EntityTypeConfiguration<Product> { public ProductConfiguration() { ToTable("Product"); HasKey(x => x.Id).Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // HAS PRECISION. // Enforces how the value is to be stored in the database // Here you can see I set a scale of 3, that's 3 digits after // the decimal. Notice how in my seed method, I gave a product 4 digits! // That means it will NOT save the product with the other trailing digits. Property(x => x.Fineness).HasPrecision(precision: 10, scale: 3); } }
With SQL Server Object Explorer, I can view my localdb Example product I made to see how EF configured my Database.
[TestFixture] public class Tests { [Test] public void Test() { Database.SetInitializer(new Initializer()); using (var ctx = new Context()) { // assert our findings that it is indeed not what we actually specified in the seed method, because of our Entity configuration with HasPrecision. Product product1 = ctx.Products.Find(1); Assert.AreEqual(145.244m, product1.Fineness); Product product2 = ctx.Products.Find(2); Assert.AreEqual(12.341m, product2.Fineness); } } }
So we need to ensure the database knows how it should store our decimal value, by configuring our entity using the model builder configuration of the Entity Framework, by using the FluentApi
, we can setup property traits through the EntityTypeConfiguration<T>
.
You do not need a EntityTypeConfiguration
, you could simply do it like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Product>().Property(x => x.Fineness).HasPrecision(10, 3); base.OnModelCreating(modelBuilder); }
If you want to change precision and scale for every decimal
you can do it like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<DecimalPropertyConvention>(); modelBuilder.Conventions.Add(new DecimalPropertyConvention(10, 3)); }
If you want a Decimal (10,3)
to round Fineness = 0.7577m
into 0.758
instead of saving 0.757
to the database have a look at the answer below. It also explains why Entity Framework 6.X truncates decimal values instead of rounds by default.
https://stackoverflow.com/a/57095584/3850405
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With