私は、データベース監査証跡を実装している最中でした。これにより、Web API プロジェクトでコントローラーを介して実行される CRUD 操作によって、古い Poco と新しい Poco がシリアル化され、後で取得できるように値が保存されます (履歴、ロールバックなど)。
すべてが機能するようになったとき、POST 中にコントローラーがどのように見えるかが気に入らなかったSaveChanges()
のは、挿入されたエンティティの ID を取得するために 1 回と、知る必要がある監査レコードをコミットするために 2 回呼び出す必要があったためです。そのID。
ID 列の代わりにシーケンスを使用するようにプロジェクト (まだ初期段階) を変換することに着手しました。これには、SQL Server からさらに抽象化するという追加のボーナスがありますが、それは実際には問題ではありませんが、コミットの数を減らすこともでき、そのロジックをコントローラーから引き出して、サービス レイヤーに詰め込むこともできます。リポジトリからコントローラーを抽象化し、この「シム」レイヤーでこの監査のような作業を行うことができます。
オブジェクトを作成し、それを公開するストアド プロシージャを作成したらSequence
、次のクラスを作成しました。
public class SequentialIdProvider : ISequentialIdProvider
{
private readonly IService<SequenceValue> _sequenceValueService;
public SequentialIdProvider(IService<SequenceValue> sequenceValueService)
{
_sequenceValueService = sequenceValueService;
}
public int GetNextId()
{
var value = _sequenceValueService.SelectQuery("GetSequenceIds @numberOfIds", new SqlParameter("numberOfIds", SqlDbType.Int) { Value = 1 }).ToList();
if (value.First() == null)
{
throw new Exception("Unable to retrieve the next id's from the sequence.");
}
return value.First().FirstValue;
}
public IList<int> GetNextIds(int numberOfIds)
{
var values = _sequenceValueService.SelectQuery("GetSequenceIds @numberOfIds", new SqlParameter("numberOfIds", SqlDbType.Int) { Value = numberOfIds }).ToList();
if (values.First() == null)
{
throw new Exception("Unable to retrieve the next id's from the sequence.");
}
var list = new List<int>();
for (var i = values.First().FirstValue; i <= values.First().LastValue; i++)
{
list.Add(i);
}
return list;
}
}
これは、ID を取得する 2 つの方法、単一の方法と範囲を提供するだけです。
これは最初の一連の単体テストではうまく機能しましたが、実際のシナリオでテストを開始するとすぐに、 を 1 回呼び出すだけで、が呼び出されるGetNextId()
まで、そのコンテキストの存続期間にわたって同じ値が返されることにすぐに気付きました。SaveChanges()
本当の利益を否定します。
2番目のコンテキストを作成する(オプションではない)か、古い学校のADO.NETに行き、直接SQL呼び出しを行い、AutoMapperを使用して同じ最終結果を得るという短い方法があるかどうかはわかりません。どちらも私には魅力的ではないので、他の誰かがアイデアを持っていることを願っています.