asp.Netcoreシリーズ24 EFモデル構成(プライマリキー、生成値、最大長さ、同時タグ)

5478 ワード

一.プライマリキー


キーは、各エンティティインスタンスのプライマリ一意識別子として使用されます.リレーショナル・データベースを使用すると、プライマリ・キーの概念にマッピングされます.プライマリ・キーではない一意の識別子を構成することもできます.IdまたはIdという名前のプロパティは、エンティティのキーとして構成されます.たとえば、次の2つの例があります.
class Car
{
   //   Car  Id  
   public string Id { get; set; }
}
class Car
{
   //   Car CarId  ,    :Id
   public string CarId { get; set; }
}

上記の規則に加えて、単一のプロパティをエンティティのキーとしてデータ・アノテーションで構成することもできます.次の例では、データ・アノテーションを使用してプライマリ・キーを構成します.
class Car
{
   //   Car LicensePlate  
    [Key]
    public string LicensePlate { get; set; }
}

また、Fluent APIを使用して、個々のプロパティをエンティティのキーとして構成することもできます.次の例では、Fluent APIを使用してプライマリ・キーを構成します.
class MyContext : DbContext
  {
      public DbSet Cars { get; set; }

      protected override void OnModelCreating(ModelBuilder modelBuilder)
      {
          modelBuilder.Entity().HasKey(c => c.LicensePlate);
      }
  }

    class Car
    {
        public string LicensePlate { get; set; }
        public string Make { get; set; }
        public string Model { get; set; }
    }

Fluent APIを使用して、複数の属性をエンティティのキー(複合キーと呼ばれる)として構成することもできます.Fluent APIを使用してのみ複合キーを構成できます.複合キーは、規則を使用して設定することはできません.また、データ注釈を使用して構成することはできません.
class MyContext : DbContext
{
    public DbSet Cars { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
            .HasKey(c => new { c.State, c.LicensePlate });
    }
}

二.生成された値


属性の値生成モードには、(1)値生成なし;(2)新規時に自動的に値を生成する.(3)追加または更新時に自動的に値を生成する.次に、データ・ノートにおけるDatabaseGeneratedOptionの列挙を使用して実装される3つの生成モードの適用シーンについて説明します.
public class Blog
{
    //     ,              ,   EF      
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int BlogId { get; set; }

    //       ,          ,       
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime Inserted { get; set; }
    
    //          ,          。
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime LastUpdated { get; set; }
}

データ・アノテーション・メソッドで値を生成するだけでなく、Fluent APIを使用して、特定の属性の値生成モードを変更することもできます.
//     
    modelBuilder.Entity().Property(b => b.BlogId).ValueGeneratedNever();
    //       
    modelBuilder.Entity().Property(b => b.Inserted).ValueGeneratedOnAdd();
    //          
    modelBuilder.Entity().Property(b => b.LastUpdated).ValueGeneratedOnAddOrUpdate();

三.最大長さ
最大長はstringやbyte[]などの配列、データ型にのみ適用されます.プロバイダにデータを渡すまで、エンティティ・フレームワークは最大長検証を実行しません.プロバイダまたはデータストレージが適切なタイミングで検証されます.SQL Serverをターゲットにして、最大長を超えると例外が発生します.
データ・コメントを使用して、プロパティの最大長を構成します.この例はSQLサーバ向けであるため、データ型nvarchar(500)が使用されます.
public class Blog
{
    public int BlogId { get; set; }
    [MaxLength(500)]
    public string Url { get; set; }
}

Fluent APIを使用してプロパティの最大長を設定します.この例はSQLサーバ向けであるため、データ型nvarchar(500)が使用されます.
modelBuilder.Entity().Property(b => b.Url).HasMaxLength(500);

四.同時タグ
コンカレントタグの構成は、データベース内のコンカレント競合を解決するために使用されます.≪データベース同時|Database Concurrent|oem_src≫:複数のプロセスまたはユーザーがデータベース内の同じデータに同時にアクセスまたは変更する場合を指します.同時制御:同時変更が発生した場合にデータの一貫性を確保するための特定のメカニズムです.
同時タグの実装は、データベースレベルのスキームではなく、EF Coreによって同時衝突の解決を実現する.EF Coreは、同期またはロックのオーバーヘッドを発生させることなく、複数のプロセスまたはユーザーが独立して変更できることを意味する楽観的な同時制御(データベースレベルではない)を実現します.理想的には、これらの変更は互いに干渉しないため、成功することができます.最悪の場合、2つ以上のプロセスが競合して変更しようとしますが、1つのプロセスだけが成功します.
4.1 EF Coreにおける同時制御の動作原理:
同時タグとして構成された属性は、SaveChanges中に更新または削除操作を実行するたびに、データベース上の同時タグ属性値とEF Coreで読み込まれた元の値とを比較する楽観的同時制御を実現するために使用されます.
(1)これらの値が一致する場合、この操作を完了することができる.
(2)これらの値が一致しない場合、EF Coreは別のユーザが競合操作を実行したと仮定し、現在のトランザクションを中止する.このことを「同時衝突」と呼ぶ.
構成およびラベル付けが完了すると、データベース・プロバイダは、値の比較を実行およびラベル付けする責任を負い、EF Coreは、任意のUPDATE文またはDELETE文のWHERE句の同時タグ値をチェックします.これらの文を実行すると、EF Coreは影響を受けるローの数を読み込みます.ローに影響がない場合は、同時競合が検出され、EF CoreによってDbUpdateConcurrencyExceptionが発生します.
たとえば、PersonのLastNameを同時タグに設定します.このように、Personの更新操作(コンカレントタグの属性は比較参照としてコンカレント競合を反映する必要があります)は、WHERE句でコンカレントチェックされ、データベース側で次のようなsqlコマンドが実行されます.条件LastNameはEFが自動的に加算されます.
 UPDATE [Person] SET [FirstName] = @p1 WHERE [PersonId] = @p0 AND [LastName] = @p2;

コンカレント・マーカーの3つの値がコンカレント・競合の解決に役立ちます.
1.「現在の値」は、アプリケーションがデータベースに書き込もうとする値です.      2.[元の値](Original Value)は、編集を行う前にデータベースから最初に取得された値です.      3.データベース値は、現在データベースに格納されている値です.コンカレント競合を生成する一般的な処理手順は、1.SaveChanges中にDbUpdateConcurrencyExceptionを取得します.      2.DbUpdateConcurrencyExceptionを使用します.Entriesは、影響を受けるエンティティの新しい変更のセットを用意します.      3.コンカレントタグの元の値をリフレッシュして、データベースの現在の値を反映します.      4.競合が発生しないまでプロセスを再試行します.次に、データ・アノテーション・メソッドを使用してLastNameプロパティをコンカレント・タグとして構成します.
public class Person
{
    public int PersonId { get; set; }

    [ConcurrencyCheck]
    public string LastName { get; set; }

    public string FirstName { get; set; }
}

次にFluent APIを使用して、LastNameプロパティをコンカレントタグとして構成します.
modelBuilder.Entity().Property(p => p.LastName).IsConcurrencyToken();

まとめ:リレーショナル・データベースの同時デッドロックは、通常、本番環境または多数のユーザー・スレッドをシミュレートした場合にのみ発生します.デッドロックの原因は、インデックスが作成されていないため、テーブルがスキャンされたり、同じ順序でオブジェクトにアクセスしなかったりするなど、さまざまです.デッドロックの原因(sqlserverデッドロック解析)(mysqlデッドロック解析)を解析してこそ,EFの同時タグと組み合わせて解決することが考えられる.
参考文献:
公式資料:メインキー
生成された値
最大長さ
同時タグ