Hi / Loアルゴリズムを使用してEntity Framework Coreでキーを生成する



Hi / Loアルゴリズムは、一意のキーが必要な場合に便利です。 つまり、Hi / Loアルゴリズムは、データベースではなくクライアント側でセキュアな識別子を生成するためのメカニズムを記述します( このコンテキストで安全とは、衝突がないことを意味します )。 行がデータベースにすぐに保存されるかどうかに依存せず、テーブルの行に一意の識別子を設定します。 これにより、通常の順次データベース識別子のように、識別子をすぐに使用できます。

データベースシーケンスはキャッシュされ、スケーリングされ、同時実行の問題を解決します。 しかし、新しいシーケンス値ごとに、常にデータベースにアクセスする必要があります。 そして、大量の挿入があると、少しオーバーヘッドになります。 したがって、シーケンスの処理を最適化するために、Hi / Loアルゴリズムが使用されます。 EntityFramework Coreは、 ForSqlServerUseSequenceHiLoメソッドを使用して、 ForSqlServerUseSequenceHiLo Hi / Loをサポートします

Hi / Loの仕組み


まず、 Hi / Loとは何ですか 。 基本的な考え方は、主キーを構成する2つの数字、つまり「高」( )番号と「低」( )番号があるということです。 クライアントは基本的に、「高」シーケンスを増やすことができます。これは、以前の「高」値の範囲全体から、多くの「低」値を持つキーを安全に生成できることを知っています。

たとえば、現在の値が35の「高い」シーケンスがあり、「低い」数値の範囲が0〜1023であるとします。 次に、クライアントはシーケンスを36に増やし(他のクライアントが35を使用するときにキーを生成できるように)、キー35 / 0、35 / 1、35 / 2、35 / 3 ... 35/1023がすべて使用可能であることを知ることができます。

主キーなしで値を挿入してからクライアントに取得する代わりに、クライアント側で主キーを設定できると(特にORMを使用して)非常に便利です。 とりわけ、これは、挿入を行う前に親と子の間の関係を簡単に作成し、すべてのキーを適切に配置できることを意味します。これにより、バッチ処理が容易になります。

Hi / Loを使用して、Entity Framework Coreでキーを生成します


Entity Framework Coreを使用して、Hi / Loを使用してキーを生成する方法を見てみましょう。 カテゴリーの単純なモデルがあるとしましょう:

 public class Category { public int Id { get; set; } public string Name { get; set; } } 

EFはIdプロパティまたは< >Idをキーとして構成することに注意してください。 次に、DBContextを作成する必要があります。

 public class SampleDBContext : DbContext { public SampleDBContext() { Database.EnsureDeleted(); Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionBuilder) { string onnString = @"Server=localhost\SQLEXPRESS01;Database=EFSampleDB;Trusted_Connection=true;"; optionBuilder.UseSqlServer(onnString); } protected override void OnModelCreating(ModelBuilder modelBuilder) { var entityTypeBuilder = modelBuilder.Entity<Category>(); entityTypeBuilder.ToTable("Category"); entityTypeBuilder.HasKey(t => t.Id); entityTypeBuilder.Property(t => t.Id).ForSqlServerUseSequenceHiLo(); entityTypeBuilder.Property(t => t.Name).HasMaxLength(128).IsRequired(); } public DbSet<Category> Category { get; set; } } 

DbContextの構成:


アプリケーションを起動します。 そのため、EFSampleDBデータベースは、CategoryテーブルとシーケンスEntityFrameworkHiLoSequenceを使用して作成する必要があります。 シーケンスの名前と、それが作成されるスキームをパラメーターとして渡すことができます。

ForSqlServerUseSequenceHiLo(string name, string schema)



「EntityFrameworkHiLoSequence」を作成するためのスクリプトは次のようになります

 CREATE SEQUENCE [dbo].[EntityFrameworkHiLoSequence] AS [bigint] START WITH 1 INCREMENT BY 10 MINVALUE -9223372036854775808 MAXVALUE 9223372036854775807 CACHE GO 

このシーケンスは1から始まり、10ずつ増加しますINCREMENT BYオプションと比較すると、 SequenceHi / Lo Sequenceには違いがあります。 シーケンスでは、 INCREMENT BYシーケンスの以前の値に値を追加して新しい値を生成します。 したがって、この場合、前のシーケンス値が11の場合、次のシーケンス値は11 + 10 = 21になりますINCREMENT BY / Loシーケンスの場合INCREMENT BYパラメーターはブロックの値を示します。つまり、次のシーケンス値が選択されます最初の10を使用します。

データベースにいくつかのデータを追加しましょう。

 using (var dataContext = new SampleDBContext()) { dataContext.Category.Add(new Category { Name = "Name-1" }); dataContext.Category.Add(new Category { Name = "Name-2" }); dataContext.Category.Add(new Category { Name = "Name-3" }); dataContext.SaveChanges(); } 

このコードがカテゴリがDBContextに追加される行に到達するとすぐに、データベースが呼び出されてシーケンス値が取得されます。 これは、SQL Server Profilerを使用して確認できます。



dataContext.SaveChanges();が呼び出されたときdataContext.SaveChanges(); 3つのカテゴリはすべて、すでに生成されて1回だけ選択されている主キー値とともに保存されます。



Lo部分がなくなるまでデータベースからシーケンス値は選択されません(この例では10レコード)。11番目のレコードを追加するときのみ、次のシーケンス値(Hi)を取得するためにデータベースが呼び出されます。

複数のテーブルからなる1つのシーケンスを作成できます。

 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ForSqlServerUseSequenceHiLo("DBSequenceHiLo"); } 

Hi / Loシーケンス設定


ForSqlServerHasSequenceメソッドには、初期値と増分値を変更するためのパラメーターがありません。 ただし、これらの値は次のように指定できます。まず、 StartAtパラメーターとIncrementByパラメーターを使用してシーケンスを決定し、次に同じForSqlServerUseSequenceHiLo拡張ForSqlServerUseSequenceHiLoを使用します。

 modelBuilder.HasSequence<int>("DBSequenceHiLo").StartsAt(1000).IncrementsBy(5); modelBuilder.ForSqlServerUseSequenceHiLo("DBSequenceHiLo"); 

この場合、DBSequenceHiLoのsqlスクリプトは次のようになります。

 CREATE SEQUENCE [dbo].[DBSequenceHiLo] AS [int] START WITH 1000 INCREMENT BY 5 MINVALUE -2147483648 MAXVALUE 2147483647 CACHE GO 

ここで、3つのカテゴリを追加すると、キー値は1000で始まります。また、 IncrementByパラメーターが「5」に設定されているため、6番目のレコードがコンテキストに追加されると、シーケンスの次の値を取得するためにデータベースに要求が行われます。 コードを変更してさらに3つのカテゴリを追加すると、画面に2番目のデータベース呼び出しが表示されます。



ご清聴ありがとうございました!

Source: https://habr.com/ru/post/J349250/


All Articles