web-dev-qa-db-ja.com

Entity Frameworkを使用してキーを手動で入力する

単純なデータベースプロジェクトで最初にEntity Frameworkコードを使用しようとしていますが、理解できない問題に遭遇します。

EFは、テーブルのIDを毎回1ずつ自動的に増加させ、そのフィールドに手動で入力した値を完全に無視していたことに気付きました。いくつかの検索の後、この動作を無効にする正しい方法が行われていることは私の理解です:

modelBuilder.Entity<Event>().Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

しかし、今私はこのエラーを取得しているだけで、理由がわかりません:

未処理の例外:System.Data.Entity.Infrastructure.DbUpdateException:エントリの更新中にエラーが発生しました。詳細については、内部例外を参照してください。 ---

System.Data.UpdateException:エントリの更新中にエラーが発生しました。詳細については、内部例外を参照してください。 ---> System.Data.SqlClient.SqlException:IDENTITY_INSERTがOFFに設定されている場合、テーブル 'Events'のID列に明示的な値を挿入できません。

役立つ場合は、問題のPOCOクラスを以下に示します。

public class Event
{
    [Key, Required]
    public int EventID { get; set; }

    public string EventType { get; set; } //TODO: Event Type Table later on
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }

    public virtual ICollection<Match> Matches { get; set; }
    public virtual ICollection<EventParticipation> EventParticipation { get; set; }
}

前もって感謝します。

45
JCafe

既定では、Entity Frameworkは、整数のプライマリキーがデータベースで生成されると想定しています(Fluent APIで属性HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)を追加するか、Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);を呼び出すことと同等です。

テーブルを作成する移行を見ると、次のように見えるはずです。

   CreateTable(
                "dbo.Events",
                c => new
                    {
                        EventID = c.Int(nullable: false, identity: true),
                        //etc
                    })
                .PrimaryKey(t => t.EventID );

次に、Fluent APIを使用してモデルをDatabaseGenerated.Noneに変更しました。 EFはこれを移行に組み込みます。

AlterColumn("dbo.Events", "EventID", c => c.Int(nullable: false, identity: false))

そして、生成されるSQLはこれです:

ALTER TABLE [dbo].[Events] ALTER COLUMN [EventID] [int] NOT NULL

これは実際に不法にしゃがみます。 IDENTITYのドロップ 列からの削除は簡単ではありません。テーブルを削除して再作成するか、新しい列を作成する必要があります。その後、データをコピーして外部キーを修正する必要があります。ですから、EFがあなたのためにそうしていないのは驚くことではありません。

あなた自身のためにそれをするための最善の方法を考え出す必要があります。 DatabaseGeneratedOption.Noneを指定したので、移行を0にロールバックして最初から再スキャフォールドするか、テーブルを削除して再作成するように移行を手動で変更できます。

または、列をドロップして再作成することもできます。

DropColumn("Customer", "CustomerId"); 
AddColumn("Customer", "CustomerId", c => c.Long(nullable: false, identity: false));

[〜#〜] edit [〜#〜]または カスタム移行操作によるIDのオン/オフ切り替え

38
Colin

私は属性を好むので、ここでは完全性のための代替案を示します。

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }

注:これはEF Coreでも機能します。

67
marsze