锁定

时间:2016-05-26 18:33:58

标签: multithreading entity-framework optimistic-concurrency

我有多个运行批处理作业的线程。当每个线程完成时,它调用我的这个方法:

        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"显然要求它没有用户返回对象...即便如此,我有时也会像这样回复用户:Getting users when there should be none

当我得到它时,我也在SaveChanges()上收到以下错误 Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded

但是,在其他时候我没有子节点正确地返回dbBatch对象,如下所示: Without Users 当我这样做时,一切都很好,没有例外。

使用调试器,我可以通过在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

DbUpdateExceptionOptimisticConcurrencyException都不包含Entries属性,因此我无法ex.Entries.Single().Reload();

我也在这里以文本形式添加例外

此处也在文本中,类型DbUpdateException的外部异常:{&#34;保存未公开其关系的外键属性的实体时发生错误。 EntityEntries属性将返回null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参阅InnerException。&#34;}

InnerException类型的OptimisticConcurrencyException:{&#34;存储更新,插入或删除语句影响了意外的行数(0)。自实体加载后,实体可能已被修改或删除。有关理解和处理乐观并发异常的信息,请参阅http://go.microsoft.com/fwlink/?LinkId=472540。&#34;}

0 个答案:

没有答案