代码之家  ›  专栏  ›  技术社区  ›  James

使用LINQ to SQL的多线程

  •  4
  • James  · 技术社区  · 15 年前

    我正在构建一个应用程序,它要求我使用DataContext的内部线程。我的申请一直在扔 InvalidOperationException 类似于:

    There is already an open DataReader associated with this Command which must be closed first

    ExecuteReader requires an open and available Connection. The connection's current state is connecting

    这些例外是间歇性的。

    以下是我的代码片段:

    var repo = new Repository();
    var entities = repo.GetAllEntities();
    foreach (var entity in entities)
    {
        ThreadPool.QueueUserWorkItem(
            delegate
            {
                try
                {
                     ProcessEntity(entity);
                }
                catch (Exception)
                {
                    throw;
                }
            });
    }
    

    我认为这可能与从主线程向线程传递实体有关,因为当我尝试访问的属性 entity .

    任何人都知道这是为什么,以及我如何解决?

    更新

    我决定这样做:

    var events = new Dictionary<int, AutoResetEvent>();
    var repo = new Repository();
    var entities = repo.GetAllEntities();
    foreach (var entity in entities)
    {
        events.Add(entity.ID, new AutoResetEvent(false));
        ThreadPool.QueueUserWorkItem(
            delegate
            {
                var repo = new Repository();
                try
                {
                    ProcessHierarchy(repo.GetEntity(entity.ID), ReportRange.Weekly);
                }
                catch (Exception)
                {
                    throw;
                }
                finally
                {
                    events[entity.ID].Set();
                }
            });
    }
    
    WaitHandle.WaitAll(events.Values.ToArray());
    

    欢迎改进/建议,但这似乎已经成功了。

    4 回复  |  直到 12 年前
        1
  •  7
  •   Elisha    15 年前

    由于实体的某些属性在上一个读卡器尚未关闭时执行新查询,因此引发异常。不能同时对数据上下文执行多个查询。

    作为解决方案,您可以“访问”您访问的属性 ProcessEntity() 并使SQL在线程之前运行。

    例如:

    var repo = new Repository();
    var entities = repo.GetAllEntities();
    foreach (var entity in entities)
    {
        var localEntity = entity; // Verify the callback uses the correct instance
        var entityCustomers = localEntity.Customers;
        var entityOrders = localEntity.Orders;
        var invoices = entityOrders.Invoices;
        ThreadPool.QueueUserWorkItem(
            delegate
            {
                try
                {
                     ProcessEntity(localEntity);
                }
                catch (Exception)
                {
                    throw;
                }
            });
    }
    

    这个解决方法将只在主线程上执行SQL,而处理将在其他线程中完成。由于所有的查询都是在单个线程中完成的,因此您在这里放松了一些效率。如果您在 处理程序() 查询也不是很重。

        2
  •  2
  •   Rory    15 年前

    尝试在新线程内创建存储库,而不是将其传入。

        3
  •  1
  •   Alex    15 年前

    请注意,SQLConnection实例不是线程安全的。不管你是否还有一个开放的读者。通常,从多个线程访问sqlconnection实例会导致不可预知的间歇性问题。

    参见: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.aspx

        4
  •  0
  •   Brian Mains    12 年前

    我的解决方案是Lightspeed持久性框架,它在8个实体之前都是免费的。每个线程创建UnitWork。

    http://www.mindscapehq.com/products/LightSpeed/default.aspx