2013-05-22 115 views
0

我读了一个VehicleMovementEvent物品的清单,其中大部分物品都是平坦的入口和出口区域。这些指标有进入或退出的指标,以及日期和时间。我使用这个列表产生一个VehiclePresence对象的列表,告诉我一辆车从开始时间到结束时间存在于x区,从两个匹配的物体收集到。我只想整个清单被处理,或者没有任何要处理的东西,所以一个交易似乎是合适的。我是否正确使用此交易?

我不经常在代码中使用事务,所以我是这样做的吗?特别是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); 
} 

回答

1

是对startsbatch变量被创建并在数据库中插入作为VehiclePresenceBatch的一部分在该方法中被添加?因为如果是这样,那么您根本不需要开始自己的交易,因为EntityFramework的方法开始自己的交易(see this)。 如果您没有使用EF,那么您只需要一个将调用封装到SaveChanges的事务,并使用ReadCommitted作为隔离级别。

如果startsBatch中的信息已经存在于数据库中,但您并不关心其他用户在阅读完之后对其进行更新,则情况与上述情况相同,并且EF将为您处理交易。

你需要多加注意只有startsBatch已经存在,你是担心其他用户\进程更新数据阅读后:

  • 一个办法是把一些并发检查中 位置,如比较保存记录时的时间戳记和提升 如果时间戳记与最初读取的时间戳记不相同。在这种情况下,EF使用的交易仍然可以。 (提供并发检查由EF或您自己的存储过程完成)

  • 其他选项,包括你的代码,其中包括一段代码,读取事务中的startsBatch 数据,并使用Repeatable ReadSerializable隔离水平。正如你所想象的那样,这使得系统 的可扩展性降低,因为它会阻止任何其他人在交易期间尝试修改\更新那些 行。 (可序列化更多 限制性,甚至防止插入新行)看看this question 和msdn herehere

作为一个经验法则,你使用SerializableRepeatable Read隔离级别时要非常小心。使用较低限制的隔离级别(如Read Commited)以及一些乐观并发检查(如果需要,通常在更新操作中)在大多数情况下应该足够了,并且性能会更好。

我也想提一下,如果您还需要交易,请考虑使用TransactionScopeOption.Required。只有当还没有环境交易时,这才会开始新的交易。因此,如果您的方法被称为另一个事务的一部分,它将成为该事务的一部分。