C# 我是否正确使用此事务处理?

C# 我是否正确使用此事务处理?,c#,.net,transactions,C#,.net,Transactions,我读了一份VehicleMovementEvent对象的列表,其中大多数对象都是进入和离开parkade区域的普通入口。它们有入口或出口的指示器,以及日期和时间。我使用此列表生成一个VehicleMovementEvent对象列表,这些对象告诉我从开始时间到结束时间,x区中存在一辆车辆,从两个匹配的VehicleMovementEvent对象中收集。我只想处理整个列表,或者什么都不处理,所以一个事务似乎是合适的 我不经常在代码中使用事务,所以,我这样做对吗?特别是w.r.t.隔离等级等 var

我读了一份
VehicleMovementEvent
对象的列表,其中大多数对象都是进入和离开parkade区域的普通入口。它们有入口或出口的指示器,以及日期和时间。我使用此列表生成一个
VehicleMovementEvent
对象列表,这些对象告诉我从开始时间到结束时间,x区中存在一辆车辆,从两个匹配的
VehicleMovementEvent
对象中收集。我只想处理整个列表,或者什么都不处理,所以一个事务似乎是合适的

我不经常在代码中使用事务,所以,我这样做对吗?特别是w.r.t.隔离等级等

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);
}

是否正在创建
startsbatch
变量并将其插入数据库中,作为在该方法中添加的
VehiclePresenceBatch
的一部分?因为如果是这样,那么您根本不需要启动自己的事务,因为EntityFramework的
DBContext.SaveChanges()
方法启动自己的事务()。 如果您没有使用EF,那么您只需要使用READCOMMITED作为隔离级别来包装对SaveChanges的调用

如果
startsBatch
中的信息已存在于数据库中,但您不关心其他用户在阅读后更新它,则您的情况与上述相同,EF将为您处理事务

只有当
startsBatch
已经存在,并且您担心其他用户\进程在阅读数据后更新数据时,您才需要更加注意:

  • 一种选择是加入一些乐观并发检查 放置,例如在保存记录和提升时比较时间戳 如果时间戳与最初读取的时间戳不同,则会出现错误。在这种情况下,EF使用的事务仍然正常。(如果并发检查由EF或您自己的存储过程完成)

  • 另一个选项是包含代码,包括读取
    startsBatch
    事务中的数据,并使用可重复读取的
    Serializable
    隔离级别。正如你所能想象的,这使得这个系统 可扩展性较差,因为它会阻止任何其他试图修改/更新这些内容的人 事务持续时间的行。(可序列化的)更多 限制性,甚至防止插入新行)请看 以及msdn和

根据经验,在使用
Serializable
Repeatable Read
隔离级别时,应该非常小心。在大多数情况下,使用限制较少的隔离级别(如
readcommitted
)和一些乐观的并发检查(如果需要的话,通常是在更新操作中)应该足够了,并且性能会更好

我还想提一下,如果您还需要一个事务,请考虑使用<代码> TraceActudiCopyEn选项。只有在还没有环境事务时,才会启动新事务。因此,如果您的方法作为另一个事务的一部分被调用,那么它将是该事务的一部分