我有多个运行批处理作业的线程。当每个线程完成时,它调用我的这个方法:
private static readonly Object lockVar = new Object();
public void UserIsDone(int batchId, int userId)
{
//Get the batch user
var batchUser = context.ScheduledUsersBatchUsers.SingleOrDefault(x => x.User.Id == userId && x.Batch.Id == batchId);
if (batchUser != null)
{
lock (lockVar)
{
context.ScheduledUsersBatchUsers.Remove(batchUser);
context.SaveChanges();
//Try to get the batch with the assumption it has no users left. If we do get the batch back, it means there are no users left.
var dbBatch = context.ScheduledUsersBatches.SingleOrDefault(x => x.Id == batchId && !x.Users.Any());
//So this must have been the last user, the batch is empty, so we fetch it and remove it.
if (dbBatch != null)
{
context.ScheduledUsersBatches.Remove(dbBatch);
context.SaveChanges();
}
}
}
}
这种方法的作用非常简单,它会查找" BatchUser"把他从队列中删除,这样做。那部分起作用了。
但是,在删除用户后,我想检查这是否是整批中的最后一个用户。但由于这是多线程的,因此可能会发生竞争。
所以我将删除批处理用户置于锁定状态,删除用户后,检查批处理是否没有批处理用户。
但这是我的问题......即使我有一个锁,并且查询得到了" dbBatch"显然要求它没有用户返回对象...即便如此,我有时也会像这样回复用户:
当我得到它时,我也在SaveChanges()上收到以下错误
但是,在其他时候我没有子节点正确地返回dbBatch对象,如下所示: 当我这样做时,一切都很好,没有例外。
使用调试器,我可以通过在lock语句上设置断点来捕获错误(参见屏幕截图1)。然后所有线程都进入锁定(一个进入)。然后我总是得到错误。 如果我在if语句中只有一个断点,它会更随机。
锁定到位后,我不知道这是怎么发生的。
更新
我Ninject我的上下文,这是我的ninject代码
kernel.Bind<MyContext>()
.To<MyContext>()
.InRequestScope()
.WithConstructorArgument("connectionStringOrName", "MyConnection");
kernel.Bind<DbContext>().ToMethod(context => kernel.Get<MyContext>()).InRequestScope();
更新2
我也试过这个解决方案https://msdn.microsoft.com/en-us/data/jj592904.aspx
但奇怪的是,我没有得到DbUpdateConcurrencyException
,而是得到DbUpdateException
InnerException
OptimisticConcurrencyException
。
但DbUpdateException
或OptimisticConcurrencyException
都不包含Entries
属性,因此我无法ex.Entries.Single().Reload();
我也在这里以文本形式添加例外
此处也在文本中,类型DbUpdateException
的外部异常:{&#34;保存未公开其关系的外键属性的实体时发生错误。 EntityEntries属性将返回null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参阅InnerException。&#34;}
InnerException
类型的OptimisticConcurrencyException
:{&#34;存储更新,插入或删除语句影响了意外的行数(0)。自实体加载后,实体可能已被修改或删除。有关理解和处理乐观并发异常的信息,请参阅http://go.microsoft.com/fwlink/?LinkId=472540。&#34;}