7

私は、レガシー データベースを、主に Entity Framework Code-First を通じてアクセスして "管理" する必要がある新しいデータベースに移行しています (矛盾しているように聞こえるかもしれません)。

MS SQL Server 2014 を使用しています。

  1. 従来のデータベースには、計算列を含むいくつかのテーブルが含まれていました。典型的な GUID と DateTime のもの。

  2. 技術的に言えば、これらの列には計算列の仕様がありませんでしたが、デフォルト値NEWID()GETDATE()

DbContext次のように、これらのプロパティを処理するように構成するのは非常に簡単です。

modelBuilder.Entity<Foo>()
            .Property(t => t.Guid)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
modelBuilder.Entity<Bar>()
            .Property(t => t.DTS)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);

上記は、エンティティ フレームワークに対して、 および の間にそのようなプロパティに指定された値を送信することを無視するように指示しINSERTsますUPDATEs

  1. しかし今、レガシー レコードのインポートを許可し、 PRIMARY KEYを含むOLD 値を維持する必要があります。IDENTITY

    1. これは、これらのレコードを挿入する際IdGuidおよびDTSプロパティをに設定する必要があることを意味します。DatabaseGeneratedOption.None

    2. の場合、Id何らかの方法SET IDENTITY_INSERT ... ON/OFFで接続セッション内で実行する必要があります。

    3. そして、このインポート プロセスも Code-First を介して実行したいと考えています。

  2. モデルを「一時的に」変更してDatabaseGeneratedOption.None、データベースの作成後にこれらのプロパティを設定すると、典型的な結果が得られます。

    データベースが作成されてから、コンテキストをサポートするモデルが変更されました。Code First Migrations を使用してデータベースを更新することを検討してください

  3. この最新バージョンのコンテキストを「確立」するために、空のコード化された移行を生成できることは理解して-IgnoreChangesいますが、これは、単に空の移行を前後に実行する必要があるため、受け入れられる戦略ではありません。この目的。


半分の答え:

これらのプロパティに null 許容型を与えることを検討しました。

public class Foo
{
    ...
    public Guid? Guid { get; set; }
}

public class Bar
{
    ...
    public DateTime? DTS { get; set; }
}

initial のデフォルト値に注意しながらDbMigration:

CreateTable(
    "dbo.Foos",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            Guid = c.Guid(nullable: false, defaultValueSql: "NEWID()"),
        })
    .PrimaryKey(t => t.Id);


CreateTable(
    "dbo.Bars",
    c => new
        {
            Id = c.Int(nullable: false, identity: true),
            DTS = c.Guid(nullable: false, defaultValueSql: "GETDATE()"),
        })
    .PrimaryKey(t => t.Id);

質問:

しかし、疑問が残ります。実行時DatabaseGeneratedOption.IdentityDatabaseGeneratedOption.Computedとを切り替える方法はありますか?DatabaseGeneratedOption.None

少なくとも、DatabaseGeneratedOption.Identity実行時にオン/オフを切り替えるにはどうすればよいでしょうか?

4

1 に答える 1

6

コンテキストの構成の一定量は、常にランタイム環境に依存します。たとえば、プロキシの生成や検証などです。そのため、Entity Framework の実行時構成は、DbContext私がかなり活用しているものです。

ユースケースごとにコンテキストの構成を切り替えるためにこのアプローチを使用したことはありませんが、これが機能しない理由はわかりません。

EntityTypeConfiguration最も単純な形式では、これは環境ごとに一連のクラスを持つことで実現できます。次に、各構成セットは、DbContext環境ごとに に接続されます。DbContext繰り返しになりますが、最も単純な形式では、これは環境ごとにタイプを持つことで実現できます。あなたの場合、これはユースケースごとになります。

あまり素朴ではありませんが、私は通常、コンテキストの構成を環境固有の作業単位にカプセル化します。たとえば、Asp.Net 環境の作業単位には、DbContext検証を Web フレームワークに委譲するように構成された基盤と、シリアル化の問題を防ぐためにプロキシ生成をオフにする構成があります。このアプローチは、あなたの問題と同様の有用性があると思います。

例(ブルートフォースコードを使用):

// Foo Configuration which enforces computed columns
public class FooConfiguration : EntityTypeConfiguration<Foo>
{
    public FooConfiguration()
    {           
        Property(p => p.DateTime).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
        Property(p => p.Guid).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed);
    }
}

// Foo configuration that allows computed columns to be overridden
public class FooConfiguration2 : EntityTypeConfiguration<Foo>
{
    public FooConfiguration2()
    {           
        Property(p => p.DateTime).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
        Property(p => p.Guid).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    }
}

// DbContext that enforces computed columns
public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new FooConfiguration());     
    }
}

// DbContext that allows computed columns to be overridden
public class MyContext2 : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new FooConfiguration2());     
    }
}

これは明らかに片付けることができます。通常、ファクトリ パターンと戦略パターンの組み合わせを使用して、ランタイム固有のコンテキストの作成をカプセル化します。これを DI コンテナーと組み合わせることで、正しいセットアップ構成クラスを環境ごとに注入することができます。

使用例:

[Fact]
public void CanConfigureContextAtRuntime()
{
    // Enforce computed columns
    using (var context = new EfContext())
    {
        var foo1 = new Foo();
        context.Foos.Add(foo1);                             
        context.SaveChanges();
    }

    // Allow overridden computed columns
    using (var context = new EfContext2())
    {              
        var foo2 = new Foo { DateTime = DateTime.Now.AddYears(-3) };
        context.Foos.Add(foo2);
        context.SaveChanges();
    }

    // etc
}
于 2014-08-15T09:40:36.083 に答える