在TransactionScope中,为稍后在事务中使用的变量调用ToList()有什么作用?

时间:2014-04-18 19:53:01

标签: entity-framework entity-framework-4

假设我创建了一个事务范围。我的主键不是自动生成的,所以我必须从数据库中获取最新值,并将此值用作要插入的值的PK。在事务中调用此snippit代码,然后将其存储到实体中。插入实体并将其保存到数据库中。

container.HourlyHealthEntries
                .Where(h => h.Date == healthEntry.Date)
                .Where(h => h.StoreGuid == healthEntry.StoreGuid)
                .OrderBy(h => h.RowIndex)
                .ToList() //we need to materialize the list since LINQ to Entity doesn't translate LastOrDefault
                .LastOrDefault();

我想知道会发生什么。是否创建了一个新事务,以便将值实现到内存中,然后在外部事务中引用?我问这个的原因是因为在多线程环境中,我们遇到了死锁。我认为这是因为我们必须阅读并插入数据库的方式。我通过删除ToList并使用OrderByDescending()来“修复”这个。我认为FirstOrDefault更容易转换为SQL。它可能只是一个速度修复,恰好可以更深层次地隐藏这个问题。想法?

1 个答案:

答案 0 :(得分:1)

这有助于最大限度地缩短查询最后一个值和保存新记录之间的时间。

您已经发现按降序排序更有效。接下来要做的只是查询Id值,而不是整个实体:

container.HourlyHealthEntries
         .Where(h => h.Date == healthEntry.Date)
         .Where(h => h.StoreGuid == healthEntry.StoreGuid)
         .Select(h => h.RowIndex)
         .OrderByDescending(i => i)
         .FirstOrDefault();

现在,最小数量的数据穿过电线,只在客户端创建一个整数。

现在立即使用此值设置PK值,并保存。

将其加入TransactionScope isolationlevel serializable

var opt = new TransactionOptions();
opt.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
using(var ts = new TransactionScope(TransactionScopeOption.Required, opt))
{
    ...

现在,当其他用户尝试修改您在事务中读取的记录时,您只会遇到冲突,但他们仍然可以阅读这些记录。