web-dev-qa-db-ja.com

不要な10進数の切り捨て

私のモデル:

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桁に切り捨てられています。

解決策-Patrickに感謝します:

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

これで、標準のエンティティモデルが定義されました。これは、idとdecimalの製品、およびその他の必要なものなどです。

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

SQL Server Object Explorerを使用すると、作成したlocaldbサンプル製品を表示して、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を使用してエンティティを構成することにより、データベースが10進値を格納する方法を認識していることを確認する必要があります。これにより、_EntityTypeConfiguration<T>_。

22
Patrick Magee

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

_Fineness = 0.7577m_をデータベースに保存する代わりに、Decimal (10,3)で_0.758_を_0.757_に丸めたい場合は、以下の回答を参照してください。また、Entity Framework6.Xがデフォルトで丸めではなく10進値を切り捨てる理由についても説明します。

https://stackoverflow.com/a/57095584/3850405

1
Ogglas

ここに良いです チュートリアル 1進数のフォーマットに

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);            // ""
0
Nikola Mitev