別のフィールドの値に応じてエンティティフレームワークのインクリメントフィールド
-
25-10-2019 - |
質問
私はエンティティフレームワークが新しく、純粋なT-SQLで非常に簡単なものに問題があります。 3列のテーブルがあると仮定します。 ID(ID、プライマリキー)、idkind(int)、number(int)。列nubmerはidkind列に依存します。この表のデータは次のようになります。
ID | idkind |番号
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 1
5 | 2 | 2
6 | 2 | 3
ご覧のとおり、列番号が自動増分されていることがわかります。idkindに依存します。 T-SQLでは、いくつかのidkindの最大(number) + 1を見つけていました。すべてが1つのトランザクションで1つのストアドプロシージャにあったため、数字の値はidkindにとってユニークでした。
エンティティフレームワークで同じことを達成する方法。数値の値は、新しいオブジェクトを作成するとき、またはidkindを変更するときに計算する必要があります。
解決
そのためにデータベーストリガーを使用して構成します Number
EFマッピングのプロパティ StoreGeneratedPattern.Computed
このプロパティがデータベースに記入され、各更新 /挿入後にリロードする必要があることをEFに通知するには。
また、新しい番号ごとにmax()を使用しません。代わりに、シーケンスをシミュレートする個別のテーブルを維持します。このテーブルには、シーケンスごとのレコードが含まれている必要があります - あなたのケースレコードあたりの記録 IdKind
現在の最大番号付き。集約を選択する代わりに、シングルレコードを選択し、新しい最大番号を含めるように更新します。このテーブルを操作することは、エンティティの永続的な変更と同じトランザクションでなければなりません。
他のヒント
同じ問題がありましたが、C#で解決しました。
エンティティをテーブルにマッピングする必要があります。
public class MyEntity
{
Kind IdKind{get; set;}
int Number{get;set;}
}
種類ごとに使用された最後の番号を保存するために、補助エンティティが必要です。
public class LastNumber
{
Kind IdKind{get;set;}
int LastNumber{get;set;}
}
次に、テーブルに行(myEntityオブジェクト)を追加する前に、親切な値に等しいLastNumberErtityの最後のnumberフィールドを使用して適切な数値を計算する必要があります。
2つの異なるスレッドが同じ種類のオブジェクトを同時に追加している可能性があるため、これらのスレッドは同じ最後の値を取得するために同じ種類のオブジェクトを追加する可能性があるため、この戦略には並行性の問題があることに注意する必要があります。この問題には、EntityFrameworkの既知のソリューションがあります。コードは次のようになる可能性があります:
public int GetNumber(Kind idKind)
{
using (var db = new MyDataContext())
{
var lastNumber = db.LastNumbers.Single(x=>x.IdKind == idKind);
for (int attemps = 0; attemps < 10;)
{
try
{
lastNumber.LastNumber++;
db.SaveChanges();
return lastNumber.LastNumber;
}
catch (DbUpdateConcurrencyException ex)
{
attemps++;
}
}
}
throw new Exception("Many concurrency calls");
}
この方法は、指定された種類の増分数を取得し、同時実行の問題を処理し、それを使用して、各myEntityオブジェクトの数値を設定できます。クライアントコードは次のようになります:
var entity = new MyEntity();
var number = GetNumber(entity.IdKind);
entity.Number = number;
db.MyEntities.Add(entity);
db.SaveChanges();
このコードをリファクタリングして、セッターをプライベートにし、工場を作成して、GetNumberメソッドを使用してエンティティが常に作成され、リポジトリを使用してDBを管理することを確認します。