Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用GetAsyncEnumerator中止正在运行的EF核心查询?_C#_Entity Framework Core - Fatal编程技术网

C# 如何使用GetAsyncEnumerator中止正在运行的EF核心查询?

C# 如何使用GetAsyncEnumerator中止正在运行的EF核心查询?,c#,entity-framework-core,C#,Entity Framework Core,我使用的是EF Core 5.0,代码如下: public async IAsyncEnumerable<Item> GetItems([EnumeratorCancellation] CancellationToken cancellationToken = default) { await using var ctx = _DbContextFunc(); //Isolationlevel is required to not cause any issues w

我使用的是EF Core 5.0,代码如下:

public async IAsyncEnumerable<Item> GetItems([EnumeratorCancellation] CancellationToken cancellationToken = default)
{
    await using var ctx = _DbContextFunc();
    //Isolationlevel is required to not cause any issues with parallel working on already read items
    await ctx.Database.BeginTransactionAsync(IsolationLevel.ReadUncommitted, cancellationToken).ConfigureAwait(false);
    await foreach (var item in ctx.Item.
        .AsSplitQuery()
        .Include(i => i.ItemDetail1)
        .Include(i => i.ItemDetail2)
        .OrderByDescending(i => i.ItemId)
        .AsNoTracking()
        .AsAsyncEnumerable()
        .WithCancellation(cancellationToken))
    {
        yield return item;
    }
}
公共异步IAsyncEnumerable GetItems([EnumeratorCancellation]CancellationToken CancellationToken=default) { 使用var ctx=_DbContextFunc()等待; //要求Isolationlevel在并行处理已读项目时不会导致任何问题 wait ctx.Database.BeginTransactionAsync(IsolationLevel.ReadUncommitted,cancellationToken).ConfigureWait(false); 等待foreach(ctx.item中的变量项)。 .AsSplitQuery() .Include(i=>i.ItemDetail1) .Include(i=>i.ItemDetail2) .OrderByDescending(i=>i.ItemId) .AsNoTracking() .AsAsAsyncEnumerable() .WithCancellation(cancellationToken)) { 收益回报项目; } } 它按预期工作,允许我在加载更多数据的同时填充datagrid。如果我取消提供的CancelationToken,首先我会在MoveNextAsync()行上得到一个TaskCanceledException,这是预期的

但是:我可以在SQL Profiler中看到,SQL查询本身并没有中止,而是始终运行,直到加载了所有数据,然后我才在同一行上得到第二个TaskCanceledException

如何中止查询本身

更新
我将AsSplitQuery()添加到示例中,因为它是我所经历的行为的原因(正如Ivan正确地猜测的)。为了缩短示例,我们省略了它…

所描述的行为是特定于某些类型的查询的EF核心实现,这些查询在内部使用了所谓的-a
DbDataReader
实现,该实现对结果进行初始化和缓冲,因此可以更早地发布底层数据读取器

很难说哪种类型的查询使用“按设计”的方式,但它肯定是在禁用/不支持时使用的

为什么??拆分查询执行多个数据库查询,并将其结果合并为单个查询。整合需要同时激活多个数据读取器。当基础数据库提供程序不支持MAR或禁用MAR(默认情况下)时,在存在活动读卡器时尝试执行第二个读卡器会导致运行时异常。因此,为了解决这个问题,EF核心必须消耗和缓冲活动读取器,并在执行下一个读取器之前释放(关闭/处置)它

由于这是使功能正常工作所必需的,因此没有外部控制方法。除非数据库提供程序支持MARS(例如,SqlServer支持),在这种情况下,您可以通过添加

MultipleActiveResultSets=True

而拆分查询将直接使用底层数据读取器,因此可以在不完全使用它们的情况下提前取消。

要知道在
OrderByDescending
查询中提供哪一项,它是否必须查询整个表才能只提供一个结果?为什么您认为此查询只返回一项?我的意思是,使用
yield
关键字一次返回一个。我可以想象,这将允许您停止枚举器的枚举,但是枚举器不需要执行整个SQL事务来生成一个项目吗?如果没有其他内容,您可以使用(var tran=wait ctx.Database.BeginTransactionAsync(IsolationLevel.ReadUncommitted,cancellationToken)将事务包装在
中.ConfigureAwait(false)){…}
然后在处理取消令牌时,您可以尝试启动
tran.Rollback()
。我不知道这是否可行,但这是我目前唯一能想到的。不,它作为一个流很好地工作,我可以从分析器中看到,即使提供了第一个结果,查询也没有完成(原始查询比这里显示的要复杂一些,但这不应该是问题)。我将尝试回滚,并让您知道它有帮助