假设我创建了一个事务范围。我的主键不是自动生成的,所以我必须从数据库中获取最新值,并将此值用作要插入的值的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。它可能只是一个速度修复,恰好可以更深层次地隐藏这个问题。想法?
答案 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))
{
...
现在,当其他用户尝试修改您在事务中读取的记录时,您只会遇到冲突,但他们仍然可以阅读这些记录。