Entity Framework のコードファーストを用いて RDB を生成する際に、POCO エンティティクラスに decimal 型のプロパティがあった場合、生成されるテーブル上のマッピングされた列の型は numeric(18,2) となります。小数点以下の桁数が2桁より多いものを格納したい場合、Fluent API を使用することで有効桁数と小数点以下の桁数を設定することができます。この方法は Stack Overflow に質問と回答がありましたが、日本語で書かれた情報はないようなので、サンプルプログラムとともに書いておきます。
FourDecimalPlaces, Amount は、POCO エンティティクラスで decimal 型のプロパティとしてあり、インスタンス生成時に 123.1234m(m は decimal 型のサフィックス)を格納しています。FourDecimalPlaces は Fluent API を用いて有効桁数を18、小数点以下の桁数を4に設定してあります。
次はデータベースエクスプローラーでそれぞれのプロパティを確認したものです。
FourDecimalPlaces は有効桁数(Precision)が18、小数点以下の桁数(Scale)が4になっていることが確認できます。
それではサンプルプログラムです。
プロジェクトは、プロジェクト名「CFFourDecimalPlaces」として、コンソールアプリケーションで作成しています。プロジェクトを作成したら、メニューの「プロジェクト」から「NuGet パッケージの管理」を選択し NuGet を使って Entity Framework をプロジェクトにインストールします。
準備ができたら、最初に POCO エンティティクラスを格納する Models フォルダを作り、Models フォルダに Sample クラスを作成します。
namespace CFFourDecimalPlaces.Models
{
public class Sample
{
public int Id { get; set; }
public string Name { get; set; }
public decimal FourDecimalPlaces { get; set; }
public decimal Amount { get; set; }
}
}
次に DAL フォルダを作り、DAL フォルダに SampleContext クラスを作成します。
using System.Data.Entity;
using CFFourDecimalPlaces.Models;
namespace CFFourDecimalPlaces.DAL
{
class SampleContext : DbContext
{
public SampleContext() : base("SampleDb") { }
public DbSet<Sample> Samples { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Fluent API を使用して decimal の有効桁数と小数点以下桁数を指定
modelBuilder.Entity<Sample>()
.Property(p => p.FourDecimalPlaces)
.HasPrecision(18, 4);
base.OnModelCreating(modelBuilder);
}
}
}
オーバーライドしている OnModelCreating(DbModelBuilder modelBuilder) メソッド内で Fluent API を使用します。.Entity<Sample>() で Sample クラスを指定し、.Property(p => p.FourDecimalPlaces) で FourDecimalPlaces プロパティを指定して、.HasPrecision(18, 4) メソッドで decimal 型の有効桁数と小数点以下桁数を設定しています(Property() メソッドの返り値でプロパティの型 decimal に対応した System.Data.Entity.ModelConfiguration.Configuration.DecimalPropertyConfiguration 型のオブジェクトが得られることで、HasPrecision() メソッドを呼び出すことができる)。
次は Program.cs です。
using System;
using System.Data.Entity;
using System.Linq;
using CFFourDecimalPlaces.DAL;
using CFFourDecimalPlaces.Models;
namespace CFFourDecimalPlaces
{
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<SampleContext>());
using (var context = new SampleContext())
{
var sample = new Sample { Name = "テスト", FourDecimalPlaces = 123.1234m, Amount = 123.1234m };
context.Samples.Add(sample);
context.SaveChanges();
}
using (var context = new SampleContext())
{
context.Samples.ToList().ForEach(n =>
Console.WriteLine("Name: {0}, FourDecimalPlaces: {1:0.0000}, Amount: {2:0.0000}",
n.Name, n.FourDecimalPlaces, n.Amount));
}
Console.WriteLine("Push any key...");
Console.ReadKey();
}
}
}
最初の using 句の中で Sample テーブルにデータを追加しています。その後 DbContext を破棄することで DbContext 内にトラッキングされたデータも破棄し、次の using 句で DB からデータを取得するようにしています(念のため、です 😛 )。
最後に、App.config に接続文字列を設定します。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="SampleDb" connectionString="Data Source=|DataDirectory|\SampleDb.sdf" providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
</entityFramework>
</configuration>
DB は SQL Server Compact 4.0 を利用して、exe ファイルの格納場所(コンソールアプリケーションなので)に SampleDb.sdf というファイル名で作成されます。