web-dev-qa-db-ja.com

Entity Framework Code First Migrations:Set Primary Key Value

次のようなテーブルのいくつかの行の追加データを格納するテーブルがあります。

public class QuoteExtra
{
    [Key]
    public int QuoteId { get; set; }
    // More fields here
}

PKを明示的に設定したこのテーブルに行を追加できるようにしたいと思います。

上記のようにそのままにしておくと、値を設定して行を送信すると、値が破棄され、データベースから自動生成された値に置き換えられます(そして、列は実際のスキーマでIdentity列として定義されます)。

これは正しい解決策のようです:

public class QuoteExtra
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int QuoteId { get; set; }
    // More fields here
}

しかし、これは代わりに私に例外を与えます:

IDENTITY_INSERTがOFFに設定されている場合、テーブル 'EnumTest'のID列に明示的な値を挿入できません。

では、EFで主キーの値を設定できるようにするには、クラスをどのように記述すればよいでしょうか。

編集:

次のコードベースの移行を追加して、IDENTITY_INSERTをONに設定してみました。

public override void Up()
{
    Sql("SET IDENTITY_INSERT QuoteExtra ON");
}

実行して再試行しましたが、上記と同じ例外が発生しました。奇妙なことに、データベースはこの設定を反映し、SQLを直接実行すると、主キーに任意の値を挿入できます。そのため、Entity Framework自体がこのルールを適用しており、IDENTITY_INSERTが含まれていないことの認識を怠っています。事実はオフに設定されています。 EF自体のどこかに設定する必要がありますか?

編集2:

IDENTITY_INSERTを誤解しました。私はそれをそのテーブルにいつまでもオンのままにしておくと仮定しました。実際、それは「セッション」の間存続します。たとえば、Migrationで設定することは、それが存続することを意味します...そのMigrationが実行されている限り存続し、EFを使用した後の.Add() 、これはなぜ私がまだその例外を受け取ったのかを説明しています-DBは実際にはEFではなく例外のソースです。 IDENTITY_INSERTはセッションごとに最大1つのテーブルに制限されているため、これを行うのはかなり非効率的な方法です。そもそもIdentity PK列を作成しない方が、より良いルートのように見えます。

20
Chris Moschini

これは、アイデンティティ自動インクリメントを有効にせずにPKを作成する適切な方法です。

public class QuoteExtra
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int QuoteId { get; set; }
    // More fields here
}

ただし、EF Migrationsが既にテーブルを作成した後でDatabaseGenerated(DatabaseGeneratedOption.None)]を追加すると、静かにテーブルに対して何も行われません。これがシナリオの場合は、テーブルを削除するために手動の移行を追加する必要があります。

add-migration RecreateQuoteExtra

そして移行では:

public override void Up()
{
    DropTable("QuoteExtra");
}

EF自動移行は、Identity制約なしでテーブルを自動的に再作成します。これにより、IDENTITY_INSERT ONなどの特別なコマンドを実行しなくても、いつでもPK値を設定できます。

これを行うための非破壊的な方法はEF7(「データモーション」)に含まれているようですが、既存のデータを失わないようにしたい場合は、移行中に手動で大量のSQLを作成して一時テーブルを作成し、データを移動することができます。テーブルに。

編集:シナリオによっては、EF Migrationsがテーブルを再作成しない場合があります-クラスがすでに存在し、DbContextにすでに追加されている場合は、それをドロップしてそのままにします。つまり、手動の移行では、ドロップするだけでなく、テーブル。 EF Migrationsがadd-migrationから生成するスキャフォールドコードはこれらのステートメントを作成するので、大したことではありませんが、問題をチェックするためのコードが少し多くなります。

34
Chris Moschini

これは正しい解決策ですが、新しいテーブルに対してのみです。既存のテーブルのデータベース生成オプションを変更した場合、EF移行ではこの変更を実行できず、QuoteId列はデータベースでIdentityとしてマークされます。

4
Ladislav Mrnka

ヒントでこの問題を解決できなかったため、データベース全体を再作成しようとしましたが、うまくいきませんでした。

これを修正するには、列の最初の(!)作成時にidentity:trueプロパティを削除する必要があります(例:Initial-Migration)。

多分それは誰かを助けるでしょう。

1
RDPP