【问题标题】:Calling SubmitChanges() in LINQ-to-SQL from multiple threads从多个线程调用 LINQ-to-SQL 中的 SubmitChanges()
【发布时间】:2012-07-19 03:51:38
【问题描述】:

我在 SO 上找到了类似的主题,但似乎没有一个可以解决我的确切问题。

基本上,我使用 .NET 任务并行库编写了一个简单的生产者/消费者应用程序。生产者每隔 30 秒检查一次数据库表中的记录。当它找到记录时,会将它们添加到BlockingQueue。同时,我使用Task.Factory对记录执行一些操作。

当即将对记录执行操作时,我想更新记录上的字段以指示它已在队列中。这样一来,如果生产者在最后一批仍在处理时检查新记录,它就不会将旧条目添加回队列。

我遇到的这个问题是从多个线程对我的数据上下文调用SubmitChanges()。我认为我正在运行一个比赛条件,但我不确定。

我得到的错误是The operation cannot be performed during a call to SubmitChanges.

生产者代码:

BlockingCollection<QueuedMessage> workItems = new BlockingCollection<QueuedMessage>();

System.Threading.Timer workItemTimer = new System.Threading.Timer((s) =>
    {
        var items = repository.GetQueuedMessages();

        foreach (var item in items)
        {
            workItems.Add(item);
        }

    }, null, 0, 30000);

消费者代码:

while (workItems.TryTake(out queuedMessage, Timeout.Infinite, new CancellationToken()))
{
    Task.Factory.StartNew((t) =>
        {
            var messageToSend = (QueuedMessage)t;

            repository.MarkQueuedMessageAsProcessing(messageToSend.Id);

            ...

            Do some stuff with messageToSend

            ....

    }, queuedMessage);
}

存储库代码:

var entity = DataContext.QueuedMessages.SingleOrDefault(m => m.Id == messageId);
entity.ProcessingStarted = true;
DataContext.SubmitChanges();

当我使用一些排队的消息运行此程序时,DataContext.SubmitChanges() 将开始抛出我之前提到的消息 The operation cannot be performed during a call to SubmitChanges. 的异常

就像我说的,我认为这是因为我从多个线程调用它,但我不确定如何解决这个问题。

我尝试将有问题的行更改为:

ThreadPool.QueueUserWorkItem(s => DataContext.SubmitChanges());

但结果是一样的。

【问题讨论】:

  • 您的 DataContext 是否跨线程共享?如果是这样,这绝对是您的问题。
  • 尝试为存储库代码中的每个更新创建一个新的数据上下文。数据上下文仅适用于单个工作单元

标签: c# asp.net multithreading linq-to-sql task-parallel-library


【解决方案1】:

您的存储库应为每次更新创建一个新的数据上下文。每一个都应该只用于a single unit of work。试试这个:

public static void ProcessingStarted(int messageId)
{
    using (DataContext dc = new DataContext())
    {
        var update = dc.QueuedMessages.SingleOrDefault(m => m.Id == messageId);
        if (update != null)
        {
            update.ProcessingStarted = true;
            dc.SubmitChanges();
        }
    }
}

【讨论】:

    【解决方案2】:

    您需要提交更改吗?如果生产者每次都使用相同的 DataContext 实例,那么它应该返回一个已经在内存中的实例。

    如果您在每次检查时使用新的 DataContext,则在新的 DataContext 上执行每个 SubmitChanges,尽管您可能需要将其从原始上下文中分离出来,并将其附加到新的上下文中,如果您想提交修改后的内容。

    【讨论】:

    • 它就像魔术一样工作。谢谢 4 分享你的经验。
    猜你喜欢
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多