"Telerik OpenAccess ORM中尝试保存更改时出现“已经有一个提交正在进行中”的错误提示。"

6
我一直在尝试找出代码中发生错误的原因。异常告诉我已经有一个提交正在进行中,但除非对SaveChanges的调用是异步的,否则我不知道这是如何发生的。
我有一个Scheduler类,其中包含多个Task对象。每个Task都有一个BackgroundWorker,在另一个线程中进行处理。然后,我在Task类中为这个BackgroundWorker完成事件设置了一个事件处理程序,并使用以下代码:
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();
}

现在,在我的理解中,我的主线程已经回来了,因为在后台工作程序中完成了任务。当我有5个任务频繁运行时,我会在SaveChanges上收到异常,说一个提交已经在进行中。我不明白这是怎么回事,因为我没有跨线程共享此上下文。我唯一能想到的是SaveChanges是异步的(不是阻塞调用)。我知道使用using语句和新的context将TaskCompleted代码包装起来可以修复它,但我想知道为什么。为什么它在当前状态下无法正常工作。

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


从你的代码中并不明显你是否有一个用户界面。这是一个服务器应用程序还是带有用户界面的应用程序?因为如果你的应用程序没有用户界面,那么BackgroundWorker可能会表现得不同。 - RogerN
@Akim 具体是什么限制? - Justin
@RogerN 很有趣。我以为 BackgroundWorker 完成事件总是在创建 BackgroundWorker 的线程上触发。知道这一点后,我不认为在许多情况下使用 BackgroundWorker 是非常有优势的。 - Justin
1
@Justin nhiberante会自动执行与数据库的同步,并且从多个线程调用“commit”,“flush”和其他操作是一个错误。 - Akim
1
请修正标题——不要发布一个薄弱的假设作为问题,而是总结问题。 - user166390
显示剩余4条评论
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();
    }
}

0

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

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

这样做会降低速度。如果你想共享 DbContext 上下文,应该保持一些计数器,每个任务增加计数器,当每个任务完成时减少计数器。最后只有当计数器再次达到零时才保存更改。


每个线程都要使用一个新的DBContext,不要计算引用次数。 - Robert Harvey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接