web-dev-qa-db-ja.com

Entity Framework auto generate GUID

私はEFが初めてなので、ここに行きます。次のものを含むクラスがあります

_public class EmailTemplate
{
    public Guid Id { get; set; }

    [MaxLength(2000)]
    public string Html { get; set; }
}
_

これが私のマッピングクラスです

_class EmailMapper : EntityTypeConfiguration<EmailTemplate>
    {
        public EmailMapper()
        {
            ToTable("EmailTemplate");

            HasKey(c => c.Id);
            Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(c => c.Id).IsRequired();
        }
    }
_

DbContext.SaveChanges()を呼び出そうとしていますが、次のエラーが表示されます。

例外の詳細:System.Data.SqlClient.SqlException:列 'Id'、テーブル 'AutoSendConnection.dbo.EmailTemplates'に値NULLを挿入できません。列はヌルを許可しません。 INSERTは失敗します。

何が間違っていますか? EFが一意のGUIDを自動作成しないのはなぜですか?

34
user2859298

以下のようにEmailTemplateクラスのIdフィールドを修飾するだけで、SQL Serverは挿入時に値を自動的に生成します。

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }

不要になったMapperクラスを削除することもできます。

49
Mark

.Netコアを使用している場合、これはあなたのために働くはずです...

Fluent APIを使用する

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Node>().Property(x => x.ID).HasDefaultValueSql("NEWID()");
}

または

modelBuilder.Entity<Student>().Property(p => p.StudentID)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

より包括的な エンティティフレームワークのチートシート

17
Mohsen Tabareh

マッピング構成で、フィールドのデフォルトのsql値を「newsequentialid()」に設定します。

4
Liviu M.

ここで他の回答に対処する

これらの他のオプションはどれも機能していないようで、githubでEFチームに何度も質問しました...

https://github.com/aspnet/EntityFramework6/issues/762

...何らかの理由でEF開発チームは、これが「設計どおりに動作している」と考えているようで、この「バグ」に疑問を投げかけるチケットを繰り返しクローズしています。

EFチームの説明

何らかの理由で、「SQLでのGUIDの生成はベストプラクティスではないと見なされ、キーをすぐに使用できるようにするには、アプリコードでキーを生成する必要がある」と考えているようです。

ここでの問題は、当然、非常に多くのテーブルが設定されているため、無効なキーを消費してさらにビジネスアクションを実行するリスクがあることです。

私の場合、これは非常に複雑なマルチサーバーDTCトランザクションを壊す可能性があるため、MSからのアドバイスが正しいとは思わない。

私の答え(実際に動作します)

要するに、生成された移行を生成した後に「手動でハッキング」することでこれを解決しました...

EFコードの最初の移行、DB生成のGUIDキー

他の質問を引用すると、答えは...

通常、次のようにキープロパティに両方の属性を設定するように移行スクリプトを生成します...

public class Foo
{
     [Key]
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
     public Guid Id { get; set; }
}

..宣言的にエンティティは正しいと言えます。

生成される移行は次のようになります。

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

...理由を特定することはできませんでしたが、状況によっては機能する場合と機能しない場合があります(移行を実行し、テストのために挿入を実行します)。

失敗した場合は、移行をロールバックし、次のように変更します...

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

...ここにある追加のコードは、SQLにキーを生成するように指示しています。

経験則として、一貫性の理由からこの変更を常に適用します。つまり、移行によって、dbが生成したキーが正確に表示されることを意味します。

2
War

IDのデフォルト値をSql Server自体でNewID()として設定し、GUID= nullとして渡すこともできます。

以前はSSMSで行っていました。

2
Moons

たとえば次のスキーマのように、データベースからIDを自動的に生成することをお勧めします。

CREATE TABLE [dbo].[MyTable](
    [MyId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Booking_BookingId]  DEFAULT (newsequentialid())
    )

次に、コードの最初のマッピングで、次を指定して、Entity Frameworkに挿入時に値を生成することをデータベースが処理することを伝えます。

Property(a => a.MyId).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
1
John