更改 IQueryable 的 DataContext

3
我正在处理一个项目,该项目使用静态全局DataContext(虽然不建议这样做,但在这一点上非常难以更改)。我目前需要通过并行化一些独立的函数来提高某些部分的性能。由于DataContext不是线程安全的,因此我不能在新创建的线程内使用它。因此,我在每个线程内创建了一个新的DataContext,并在线程结束时将其释放。
新的datacontext一切正常,但我的问题是,函数的一个输入是与Global DataContext关联的IQueryable。运行该方法将导致“已经有一个与该命令相关联的打开的DataReader必须首先关闭”的异常。
问题是,我如何能够使用新的数据上下文而不是更改后的上下文来运行IQueryable。
以下是线程的示例代码:
var myQueryable = Global.DataContext.Customers.Where(a => a.Age <12);

ParallelLoopResult threads = Parallel.ForEach(groups, group =>
        {
            DataContext ctx = new DataContext(Const.ConnectionString);
            myFunction(myQueryable);
            ctx.Dispose();
        });

把 myQueryable 重写到线程中的选项非常困难,因为有大量的逻辑需要生成它。将其转换为列表然后传递也不是一个选项,因为查询返回数千个条目,会对性能产生负面影响。

非常感谢任何帮助。


1
为什么不创建一个新的,与之相同的IQueryable呢?将其创建封装在一个接受上下文作为参数的函数中,并从任何您想要的地方创建查询。此外,可查询对象将在特定上下文中运行的查询 - 您无法更改其父项。这是您不应该拥有全局上下文的非常重要的原因之一。 - Panagiotis Kanavos
我完全同意你的观点。但是之前的开发人员选择了这种方法,生成IQueryable的部分紧密耦合。因此,我希望找到一种将查询附加到不同DataContext的最简单和最快的解决方法。但似乎唯一的方法是更改该代码以接受DataContext作为参数。谢谢。 - Sami
1
查询对象是已经准备好执行的查询,它们不是查询定义。顺便问一下,你为什么要尝试并行执行多个查询对象?这样做并不会使任何东西运行更快(相反地)。你是否认为并行处理可以解决性能问题?编写良好的SQL语句和适当的索引远比并行处理有效(有效度高达数千倍)。 - Panagiotis Kanavos
也许我对于并行部分提高性能的想法是错误的,但它仅仅是一个临时方案。目前的代码在for循环中运行n个读取查询。每个查询需要一秒钟的运行时间。因此所有查询的总和是很多的。我正在尝试通过将独立的查询分开运行来快速加速,直到我们重新编写这些函数。重写整个部分是正确的做法,但需要几周的时间。我只是希望能够快速改善。 - Sami
1
您可能还需要研究批处理多个查询以避免网络往返成本。如果每个查询需要1秒,则网络成本是一个重要因素。在EF中,您可以通过EntityFramework.Extended包和Future Queries来实现这一点。它还提供了批量更新/删除的支持。 - Panagiotis Kanavos
非常好,非常感谢你的建议。 - Sami
1个回答

5

我没有测试过,但是我认为可能会有用的方法是使用正确的Expression获取你的可查询对象,但是错误的Provider与具有正确Provider但是错误的Expression的对象结合起来。要做到这一点,请使用CreateQuery()函数:

var contextQueryable = ctx.Customers.AsQueryable();

var fixedQueryable = contextQueryable.Provider.CreateQuery<Customer>(myQueryable.Expression);

这可能会起作用。查询包含对Datacontext对象(如表/实体集)的引用,但是也许提供程序并不依赖于此。 - usr
@usr 你说得对,同样在 Expression 中切换 DataContext(可能使用 ExpressionVisitor)会更加安全。 - svick

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