0

オブジェクトのリストを読みましたがVehicleMovementEvent、そのほとんどは駐車場ゾーンへの単純な出入り口です。これらには、入口または出口のインジケータと、日付と時刻があります。VehiclePresenceこのリストを使用して、車両が開始時刻から終了時刻までゾーン x に存在していたことを示すオブジェクトのリストを生成します。これは、2 つの一致するVehicleMovementEventオブジェクトから収集されます。リスト全体を処理するか、何も処理しないようにしたいので、トランザクションが適しているようです。

コードでトランザクションを使用することはあまりありません。特に分離レベルなどについて。

var opts = new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead, Timeout = new TimeSpan(0, 0, 10, 0) };
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew, opts))
{
    var vehicleMovements = startsbatch.Movements
                                .Where(m => m.MovementType.Direction == VehicleMovementEventType.Entry)
                                .OrderBy(m => m.EmpNo)
                                .ThenBy(m => m.MovementDateTime);


    presenceBatch.StartDateTime = DateTime.Now;
    presenceBatch.MovementBatch = startsbatch;
    _dbContext.VehiclePresenceBatches.Add(presenceBatch);
    _procTrace.TraceInformation("New VehiclePresencesBatch created. Id: {0}.", presenceBatch.Id);

    foreach (var movement in vehicleMovements)
    {
        var presence = new VehiclePresence 
                            {
                                PresenceBatch = presenceBatch,
                                EmpNo = movement.EmpNo,
                                Location = movement.Location,
                                StartDateTime = movement.MovementDateTime,
                                StartMovementBatchId = movement.BatchId,
                                StartMovementLineId = movement.LineId,
                                StartMovementId = movement.Id
                            };
        _dbContext.VehiclePresences.Add(presence);
        returnList.Add(presence);
    }
    _dbContext.SaveChanges();
    scope.Complete();
    _procTrace.TraceInformation("{0} VehicleMovements processed. {1} VehiclePresences created", vehicleMovements.Count(), returnList.Count);
}
4

1 に答える 1

1

変数は、そのメソッドに追加さstartsbatchれる一部として作成され、データベースに挿入されていますか? その場合、EntityFramework のメソッドがVehiclePresenceBatch独自のトランザクションを開始するため、独自のトランザクションを開始する必要がまったくないためです(これを参照)。EF を使用していない場合は、ReadCommitted を分離レベルとして使用して、SaveChanges への呼び出しをラップするトランザクションが必要になります。DBContext.SaveChanges()

情報がstartsBatchデータベースに既に存在しているが、それを読んだ後に他のユーザーがそれを更新することを気にしない場合は、上記と同じ状況にあり、EF がトランザクションを処理します。

startsBatch既に存在し、それを読んだ後に他のユーザー/プロセスがそのデータを更新することを心配している場合にのみ、さらに注意を払う必要があります。

  • 1 つのオプションは、レコードを保存するときにタイムスタンプを比較し、タイムスタンプが最初に読み取ったものと同じでない場合にエラーを発生させるなど、いくつかの楽観的な同時実行チェックを配置することです。この場合、EF が使用するトランザクションは問題ありません。(並行性チェックが EF または独自のストアド プロシージャによって行われることを提供します)

  • startsBatch もう 1 つのオプションは、トランザクション内のデータを読み取り、Repeatable Readまたは Serializable分離レベルを使用するコードを含めて、コードを含めることです。ご想像のとおり、これにより、トランザクション中にこれらの行を変更または更新しようとする他のユーザーがブロックされるため、システムのスケーラビリティが低下します。(Serializable はより制限的で、新しい行が挿入されないようにすることさえできます) this question と msdn herehereを見てください。

経験則として、分離レベルを使用するときは十分に注意する必要がSerializableありRepeatable Readます。Read Commitedほとんどの場合、楽観的な同時実行性チェック (必要な場合、通常は更新操作で) を使用して、より制限の少ない分離レベルを使用することで十分であり、パフォーマンスが向上します。

また、まだトランザクションが必要な場合は、 の使用を検討してTransactionScopeOption.Requiredください。これは、まだアンビエント トランザクションがない場合にのみ、新しいトランザクションを開始します。したがって、メソッドが別のトランザクションの一部として呼び出された場合、それはそのトランザクションの一部になります。

于 2013-05-22T16:55:29.807 に答える