web-dev-qa-db-ja.com

列タイプを設定するために、すべてのEFモデルのすべてのプロパティをループ/反映

クライアントには、decimal(13,4)仕様のSQL Serverの10進数を格納する標準があります。その結果、非常に大きくてまだ成長しているスキーマでは、次のような100近くのステートメントがあります。

builder.Entity<MyObject>()
    .Property(x => x.MyField1)
    .ForSqlServerHasColumnType("decimal(13,4)");
builder.Entity<MyObject>()
    .Property(x => x.MyField2)
    .ForSqlServerHasColumnType("decimal(13,4)");
builder.Entity<MyObject2>()
    .Property(x => x.MyField1)
    .ForSqlServerHasColumnType("decimal(13,4)");

デフォルトですべての小数がdecimal(13,4)であることをEFに直接伝えることができる機能がある場合、それを使用したいと思います。そうでない場合は、リフレクションを使用してモデル内のすべてのオブジェクト/プロパティをループできるので、これをいくつかのステートメントで実行できますか?

何かのようなもの:

foreach(var efObj in EntityFrameWorkObjects)
{
    foreach (var objProperty in efObj)
    {
        if (objProperty is decimal || objProperty is decimal?)
        {
            builder.Entity<efObj>()
                .Property(x => x.efObj)
                .ForSqlServerHasColumnType("decimal(13,4)");
        }
    }
}

オブジェクトに名前と説明がある場合、名前は必須で256文字に制限される他のいくつかの規則を実装できるため、リフレクションは素晴らしい方法のように思えます。

pdate: Ivanのコメントにあるリンクをたどり、これに合わせました。

foreach (var p in builder.Model
    .GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => 
        p.ClrType == typeof(decimal) ||
        p.ClrType == typeof(decimal?)))
{
    p.SqlServer().ColumnType = "decimal(13,4)";
}

その後まもなく、彼は完全な回答を提供しましたが、10進数とnull許容可能な10進数の両方で機能するように少し変更しました。

foreach (var pb in builder.Model
    .GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => 
        p.ClrType == typeof(decimal) ||
        p.ClrType == typeof(decimal?))
    .Select(p => 
        builder.Entity(p.DeclaringEntityType.ClrType)
            .Property(p.Name)))
{
    pb.ForSqlServerHasColumnType("decimal(13,4)");
}

どちらの方法でも機能します。

pdate 2:上記を機能させるには、コンテキスト内でオブジェクトをDbSet <>として宣言する必要がありました。プロパティを1行ずつ設定する場合、これは必要ないようです。

18
Chris

EF Core v1.1.0では、次のようなものを使用できます。

foreach (var pb in modelBuilder.Model
    .GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?))
    .Select(p => modelBuilder.Entity(p.DeclaringEntityType.ClrType).Property(p.Name)))
{
    pb.ForSqlServerHasColumnType("decimal(13,4)");
}

pdate: EF Core 2.0以降、モデルはデータベースプロバイダーごとに個別に構築されるため、HasAbcXyzメソッドは共通のHasXyzに置き換えられます。更新されたコード(明示的に構成されたプロパティもスキップします)は次のようになります。

foreach (var property in modelBuilder.Model.GetEntityTypes()
    .SelectMany(t => t.GetProperties())
    .Where(p => p.ClrType == typeof(decimal) || p.ClrType == typeof(decimal?)))
{
    if (property.Relational().ColumnType == null)
        property.Relational().ColumnType = "decimal(13,4)";
}
30
Ivan Stoev