6

我一直在试图弄清楚我的代码中是如何发生错误的。异常告诉我提交已经在进行中,但除非调用SaveChanges是异步的,否则我看不到这是如何发生的。

我有一个Scheduler包含多个Task对象的类。每个Task都有一个BackgroundWorker在另一个线程中进行处理的。然后,我在类中有一个用于此 BackgroundWorker 完成事件的事件处理程序,Task代码如下:

private void TaskWorkCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (!(e.Result is TaskResult))
        throw new ArgumentException("Result must be a TaskResult class.");

    TaskComplete((TaskResult)e.Result);
}

还在我这儿?所以我的任务类中有这个事件处理程序,它触发TaskComplete我在主Scheduler类中使用以下代码处理的事件:

private void TaskCompleted(object sender, TaskCompletedEvent e)
{
    Model.Task scheduledTask = entitySet.Tasks.First(x => x.TaskName == e.ClassName);
    TaskLog logMsg = new TaskLog()
    {
        //stuff here
    };

    scheduledTask.TaskLogs.Add(logMsg);
    entitySet.SaveChanges();
}

现在,据我了解,我回到了我的主线程,因为在我的 backgroundworker 中完成的工作已经完成。当我有 5 个任务非常频繁地运行时,我在 SaveChanges 上收到一个异常,说提交已经在进行中。我不明白这是怎么回事,因为我没有跨线程共享这个上下文。我可以看到这种情况发生的唯一方法是 SaveChanges 是异步的(不是阻塞调用)。我知道用 using 语句将代码包装在 TaskCompleted 中,新的上下文可以解决它,但我想知道为什么。以及为什么不能在当前状态下工作。

最后一件事,我正在使用 Telerik 的 OpenAccess ORM。

4

2 回答 2

0

尝试像这样同步提交:

private static object _syncObject = new object();

private void TaskCompleted(object sender, TaskCompletedEvent e)
{
    Model.Task scheduledTask = entitySet.Tasks.First(x => x.TaskName == e.ClassName);
    TaskLog logMsg = new TaskLog()
    {
        //stuff here
    };

    scheduledTask.TaskLogs.Add(logMsg);
    lock(_syncObject){
        entitySet.SaveChanges();
    }
}
于 2013-02-02T19:51:33.113 回答
0

您可能DbContext在多个线程之间共享一个。

如果您想在多线程环境中使用数据库,最好在开始处理对象之前分离对象(即不使用代理或延迟加载)。然后只需DbContext为每个任务创建一个新的,附加对象,然后保存更改。

但是,这会降低速度。如果您想共享DbContext上下文,您可能应该保留一些计数器,该计数器随每个任务增加,然后在每个任务完成时减少。最后仅在计数器再次达到零时保存更改。

于 2013-02-04T15:24:32.963 回答