Подтвердить что ты не робот

Нежелательная десятичная усечка

Моя модель:

public class Product
{
    ...
        public decimal Fineness { get; set; }
    ...
}

Посещение базы данных:

new List<Product>
        {
            new Product { ..., Fineness = 0.757M, ... },
            new Product { ..., Fineness = 0.674M, ... },
            new Product { ..., Fineness = 0.475M, ... }
        }.ForEach(p => context.Products.Add(p));

Запрос базы данных для проверки посева:

var products = db.Products.ToList();
foreach (var p in products)
{
    S.D.Debug.WriteLine("ProductList: {0}, {1}", p.Name, p.Fineness);
}

Выход консоли:

ProductList: Test Product, 0.75 
ProductList: Test Product, 0.67 
ProductList: Test Product, 0.47    

Я делаю что-то действительно глупое или что-то??? Все усекается до 2 знаков после запятой.

Решение - благодаря Патрику:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>().Property(x => x.Fineness).HasPrecision(10, 5);
}
4b9b3361

Ответ 1

Итак, у вас есть определенные стандартные модели сущностей, вот продукт с идентификатором и десятичным значком, а также все, что вам нужно и т.д.

public class Product
{
    public int Id { get; set; }
    public decimal Fineness { get; set; }
}

Итак, я определил инициализатор, и в этом случае база данных будет удаляться и воссоздавать любую предоставленную информацию о посеве, каждый раз, когда я запускаю и выполняю мое приложение, это будет вызываться.

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 explicitliy 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 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);
    }
}

С помощью Обозревателя объектов SQL Server я могу просмотреть свой файл localdb Example, который я сделал, чтобы увидеть, как EF настроил мою базу данных.

enter image description here

[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);
        }         
    }
}

Unit Test has run, seeded the db and we asserted our assumption

Таким образом, нам нужно обеспечить, чтобы база данных знала, как она должна хранить наше десятичное значение, путем настройки нашего объекта с помощью конфигурации построителя модели Entity Framework, используя FluentApi, мы можем настроить свойства с помощью EntityTypeConfiguration<T>.

Ответ 2

Здесь хорошо учебник для форматирования десятичных чисел

D.Debug.WriteLine("ProductList: {0}, {1:0.000}", p.Name, p.Fineness);

// just two decimal places
String.Format("{0:0.00}", 123.4567);      // "123.46"
String.Format("{0:0.00}", 123.4);         // "123.40"
String.Format("{0:0.00}", 123.0);         // "123.00"

// max. two decimal places
String.Format("{0:0.##}", 123.4567);      // "123.46"
String.Format("{0:0.##}", 123.4);         // "123.4"
String.Format("{0:0.##}", 123.0);         // "123"

// at least two digits before decimal point
String.Format("{0:00.0}", 123.4567);      // "123.5"
String.Format("{0:00.0}", 23.4567);       // "23.5"
String.Format("{0:00.0}", 3.4567);        // "03.5"
String.Format("{0:00.0}", -3.4567);       // "-03.5"

//Zero formatting
String.Format("{0:0.0}", 0.0);            // "0.0"
String.Format("{0:0.#}", 0.0);            // "0"
String.Format("{0:#.0}", 0.0);            // ".0"
String.Format("{0:#.#}", 0.0);            // ""

Ответ 3

Вам не нужно EntityTypeConfiguration, вы можете просто сделать это так:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>().Property(x => x.Fineness).HasPrecision(10, 3);

    base.OnModelCreating(modelBuilder);
}

Если вы не хотите менять точность и масштаб для каждого decimal вы можете сделать это следующим образом:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<DecimalPropertyConvention>();
    modelBuilder.Conventions.Add(new DecimalPropertyConvention(10, 3));
}

Если вы не хотите, чтобы Decimal (10,3) Fineness = 0.7577m до 0.758 вместо сохранения 0.757 в базе данных, взгляните на ответ ниже. Также объясняется, почему Entity Framework 6.X по умолчанию обрезает десятичные значения вместо округлений.

fooobar.com/info/704266/...