Dapper:关闭 reader 时尝试调用 NextResult 无效
Dapper: Invalid attempt to call NextResult when reader is closed
我在尝试使用 .NET 5.0、Dapper 2.0.78 异步和 MSSQL 服务器执行多个语句时出现以下错误 - 有时 -
System.InvalidOperationException: Invalid attempt to call NextResult
when reader is closed. at
Microsoft.Data.SqlClient.SqlDataReader.TryNextResult(Boolean& more)
at Microsoft.Data.SqlClient.SqlDataReader.NextResult() at
Dapper.SqlMapper.GridReader.NextResult() in
//Dapper/SqlMapper.GridReader.cs:line 414 at
Dapper.SqlMapper.GridReader.ReadDeferred[T](Int32 index, Func 2
deserializer, Type effectiveType)+System.IDisposable.Dispose() at
Dapper.SqlMapper.GridReader.ReadDeferred[T](Int32 index, Func 2
deserializer, Type effectiveType)+MoveNext() in
//Dapper/SqlMapper.GridReader.cs:line 384 at
System.Collections.Generic.List 1..ctor(IEnumerable 1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
它不会一直发生。我怀疑 SQL 连接被无意关闭。有什么问题吗?
为了调试,我测试了 SQL 语句并查看了 SSMS 中的执行计划 - 这里没有任何标记,即正确的索引、配置的主键,它在很短的时间内执行。
SQL 服务器有
- 16 GB 内存
- SQL Server 2016 最新更新
- 英特尔至强 E5-2630 v4 @ 2.2 GHz,6 个虚拟处理器。
这是我的代码,比较简单。
private async Task<RecipeListModel> GetRecipesByIngredientAsync(int id)
{
string sql = @"SELECT Id,Title FROM dbo.[Ingredients] WHERE Id = @id;
SELECT ID,Title FROM dbo.[Recipes] WHERE IngredientId = @Id;" // simplified for the example
RecipeListModel model = new() { };
using (SqlConnection conn = new("my connection here"))
{
var data = await conn.QueryMultipleAsync(sql, new { id }).ConfigureAwait(false);
model = new RecipeListModel
{
Ingredient = data.ReadAsync<Ingredient>().Result.SingleOrDefault(),
Recipes = data.ReadAsync<Recipe>().Result.ToList()
};
}
return model; // exception happens here.
}
public class Ingredient
{
public int Id { get; set; }
public string Title { get; set; }
// ...
}
public class Recipe
{
public int Id { get; set; }
public string Title { get; set; }
// ...
}
public class RecipeListModel
{
public IEnumerable<Recipe> Recipes { get; set; }
public Ingredient Ingredient { get; set; }
// ...
}
根据评论更新:
[Route("~/{lang}/ingredient/{title}-{id}", Name = "ingredient-view")]
public async Task<IActionResult> Ingredient(string title, int id, string q, int page = 1)
{
if (ModelState.IsValid)
{
var model = await GetRecipesByIngredientAsync(page, id, title, q).ConfigureAwait(false);
if (model.Ingredient == null || Common.ClearUrl(model.Ingredient.Title) != title) // for SEO purposes, make sure that we do not have a tampered URL
{
return NotFound();
}
if (model.Recipes.Any())
{
var total = model.Recipes.First().TotalRows;
model.TotalRows = total;
model.Pager = new Pager(total, page, 8);
model.q = string.IsNullOrEmpty(q) ? "" : q.ToString();
return View(model);
}
else
{
RecipeListModel empty = new()
{
Recipes = new List<Recipe>() { new Recipe() { Title = "" } },
Pager = new Pager(0, 0, 1),
q = q
};
return View(empty);
}
}
return NotFound();
}
private async Task<RecipeListModel> GetRecipesByIngredientAsync(int p, int id, string title, string q)
{
string searchSql = @" -- optional (search phrase can be empty)
INNER JOIN FREETEXTTABLE([dbo].[FT_Recipes_v], *, @SearchPhrase, LANGUAGE 'English') AS recipesFullSearch
ON(r.Id = recipesFullSearch.[Key])";
string sql = string.Format(@"SELECT Id,Title FROM dbo.[Ingredients] WHERE Id = @id;
;WITH RowCounter AS (
SELECT COUNT(r.Id) as TotalRows
FROM
[dbo].[Recipes] r
INNER JOIN [dbo].[RecipeIngredients] RI ON RI.Recipe_Id = r.Id
INNER JOIN [dbo].[Ingredients] I ON RI.Ingredient_Id = I.Id
{0} -- inject search phrase here if not empty
WHERE
[Active] = 1 AND [Approved] = 1
AND I.Id = @Id
),
DataRows AS (
SELECT
r.Id
,STUFF( -- combine all tags into a 'csv list' like pepper[i:123]salt[i:124]...
(
SELECT TOP 3
']' + Title + '[i:' + CAST(Ingredient_Id AS nvarchar(11)) [text()]
FROM
(
SELECT
RI.Recipe_Id
,RI.Ingredient_Id
,I.Title
FROM dbo.RecipeIngredients AS RI
INNER JOIN dbo.Ingredients AS I
ON RI.Ingredient_Id = I.Id
-- here's the relation to the main query
WHERE RI.Recipe_Id = r.Id
) TempTable
FOR XML PATH(''), TYPE
).value('.','nvarchar(max)'),1,1,''
) IngredientsCSV
,r.Title
,LEFT(r.Description,260) as Description
,d.Title AS DishTypeTitle
,I.Title AS IngredientTitle
,RF.[file]
FROM
[dbo].[Recipes] r
INNER JOIN [dbo].[DishTypes] d ON r.DishType_Id = d.Id
INNER JOIN [dbo].[RecipeIngredients] RI ON RI.Recipe_Id = r.Id
INNER JOIN [dbo].[Ingredients] I ON RI.Ingredient_Id = I.Id
{0} -- inject search phrase here if not empty
OUTER APPLY
(SELECT TOP 1 recipe_id,[file] FROM dbo.RecipeFiles WHERE recipe_id = r.id ) RF
WHERE
[Active] = 1 AND [Approved] = 1 AND I.[Id] = @Id
ORDER BY
r.Id DESC
OFFSET (@PageNumber) ROWS
FETCH FIRST (@RowsPerPage) ROWS ONLY
)
SELECT
dr.*,
(select TotalRows from rowcounter) as TotalRows
FROM
DataRows dr;"
, !string.IsNullOrEmpty(q) ? searchSql : ""
);
using (SqlConnection conn = new("data source=someip;initial catalog=mydb;persist security info=True;user id=u;password=p"))
{
using (var data = await conn.QueryMultipleAsync(sql, new
{
SearchPhrase = q,
id,
PageNumber = (p - 1) * 8,
RowsPerPage = 8
}).ConfigureAwait(false))
{
return new RecipeListModel
{
Ingredient = await data.ReadSingleOrDefaultAsync<Ingredient>().ConfigureAwait(false),
Recipes = await data.ReadAsync<Recipe>().ConfigureAwait(false)
};
}
}
}
这是完整的事件日志(注意 NextResultAsync 而不是之前的 NextResult:
RequestPath: /ingredient/pepper-123
An unhandled exception has occurred while executing the request.
Exception: System.InvalidOperationException: Invalid attempt to call
NextResultAsync when reader is closed. at
Microsoft.Data.Common.ADP.ExceptionWithStackTrace(Exception e)
--- End of stack trace from previous location --- at Dapper.SqlMapper.GridReader.NextResultAsync() in
/_/Dapper/SqlMapper.GridReader.Async.cs:line 157 at
Dapper.SqlMapper.GridReader.ReadBufferedAsync[T](Int32 index, Func2 deserializer) in /_/Dapper/SqlMapper.GridReader.Async.cs:line 241 at myproject.Controllers.HomeController.GetRecipesByIngredientAsync(Int32 p, Int32 id, String title, String q) in C:\Web\myproject\myproject-net\Controllers\HomeController.cs:line 502 at myproject.Controllers.HomeController.Ingredient(String title, Int32 id, String q, Int32 page) in C:\Web\myproject\myproject-net\Controllers\HomeController.cs:line 125 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask
1 actionResultValueTask) at
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker
invoker, Task lastTask, State next, Scope scope, Object state, Boolean
isCompleted) at
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed
context) at
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State&
next, Scope& scope, Object& state, Boolean& isCompleted) at
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker
invoker, Task lastTask, State next, Scope scope, Object state, Boolean
isCompleted) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker
invoker, Task lastTask, State next, Scope scope, Object state, Boolean
isCompleted) at
Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilder.<>c.<b__8_0>d.MoveNext()
--- End of stack trace from previous location --- at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext
context) at
Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext
context) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker
invoker, Task lastTask, State next, Scope scope, Object state, Boolean
isCompleted) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed
context) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State&
next, Scope& scope, Object& state, Boolean& isCompleted) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker
invoker, Task lastTask, State next, Scope scope, Object state, Boolean
isCompleted) at
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker
invoker, Task task, IDisposable scope) at
Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint
endpoint, Task requestTask, ILogger logger) at
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext
context) at
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext
context) at
SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext
context) at
Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext
context) at
WebMarkupMin.AspNetCore2.WebMarkupMinMiddleware.ProcessAsync(HttpContext
context, Boolean useMinification, Boolean useCompression) at
WebMarkupMin.AspNetCore2.WebMarkupMinMiddlewareBase.Invoke(HttpContext
context) at
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware
middleware, HttpContext context, Task task)
我不能肯定地说,但它似乎是 ReadSingleOrDefaultAsync
中的一个错误,导致它关闭连接。
我们的想法是在关闭连接之前完全读取所有结果集,因此您需要使用能够做到这一点的东西。这可能是 foreach
、ToList
、ToDictionary
或 SingleOrDefault
。
所以改用 ReadAsync
并将其输入标准 SingleOrDefault
。
model = new RecipeListModel
{
Ingredient = (await data.ReadAsync<Ingredient>().ConfigureAwait(false)).SingleOrDefault(),
Recipes = (await data.ReadAsync<Recipe>().ConfigureAwait(false)).ToList(),
}
我希望有机会调试 Dapper 源代码,并更新此答案以准确说明问题所在。
我在尝试使用 .NET 5.0、Dapper 2.0.78 异步和 MSSQL 服务器执行多个语句时出现以下错误 - 有时 -
System.InvalidOperationException: Invalid attempt to call NextResult when reader is closed. at Microsoft.Data.SqlClient.SqlDataReader.TryNextResult(Boolean& more)
at Microsoft.Data.SqlClient.SqlDataReader.NextResult() at Dapper.SqlMapper.GridReader.NextResult() in //Dapper/SqlMapper.GridReader.cs:line 414 at Dapper.SqlMapper.GridReader.ReadDeferred[T](Int32 index, Func 2 deserializer, Type effectiveType)+System.IDisposable.Dispose() at Dapper.SqlMapper.GridReader.ReadDeferred[T](Int32 index, Func 2 deserializer, Type effectiveType)+MoveNext() in //Dapper/SqlMapper.GridReader.cs:line 384 at System.Collections.Generic.List 1..ctor(IEnumerable 1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
它不会一直发生。我怀疑 SQL 连接被无意关闭。有什么问题吗?
为了调试,我测试了 SQL 语句并查看了 SSMS 中的执行计划 - 这里没有任何标记,即正确的索引、配置的主键,它在很短的时间内执行。 SQL 服务器有
- 16 GB 内存
- SQL Server 2016 最新更新
- 英特尔至强 E5-2630 v4 @ 2.2 GHz,6 个虚拟处理器。
这是我的代码,比较简单。
private async Task<RecipeListModel> GetRecipesByIngredientAsync(int id)
{
string sql = @"SELECT Id,Title FROM dbo.[Ingredients] WHERE Id = @id;
SELECT ID,Title FROM dbo.[Recipes] WHERE IngredientId = @Id;" // simplified for the example
RecipeListModel model = new() { };
using (SqlConnection conn = new("my connection here"))
{
var data = await conn.QueryMultipleAsync(sql, new { id }).ConfigureAwait(false);
model = new RecipeListModel
{
Ingredient = data.ReadAsync<Ingredient>().Result.SingleOrDefault(),
Recipes = data.ReadAsync<Recipe>().Result.ToList()
};
}
return model; // exception happens here.
}
public class Ingredient
{
public int Id { get; set; }
public string Title { get; set; }
// ...
}
public class Recipe
{
public int Id { get; set; }
public string Title { get; set; }
// ...
}
public class RecipeListModel
{
public IEnumerable<Recipe> Recipes { get; set; }
public Ingredient Ingredient { get; set; }
// ...
}
根据评论更新:
[Route("~/{lang}/ingredient/{title}-{id}", Name = "ingredient-view")]
public async Task<IActionResult> Ingredient(string title, int id, string q, int page = 1)
{
if (ModelState.IsValid)
{
var model = await GetRecipesByIngredientAsync(page, id, title, q).ConfigureAwait(false);
if (model.Ingredient == null || Common.ClearUrl(model.Ingredient.Title) != title) // for SEO purposes, make sure that we do not have a tampered URL
{
return NotFound();
}
if (model.Recipes.Any())
{
var total = model.Recipes.First().TotalRows;
model.TotalRows = total;
model.Pager = new Pager(total, page, 8);
model.q = string.IsNullOrEmpty(q) ? "" : q.ToString();
return View(model);
}
else
{
RecipeListModel empty = new()
{
Recipes = new List<Recipe>() { new Recipe() { Title = "" } },
Pager = new Pager(0, 0, 1),
q = q
};
return View(empty);
}
}
return NotFound();
}
private async Task<RecipeListModel> GetRecipesByIngredientAsync(int p, int id, string title, string q)
{
string searchSql = @" -- optional (search phrase can be empty)
INNER JOIN FREETEXTTABLE([dbo].[FT_Recipes_v], *, @SearchPhrase, LANGUAGE 'English') AS recipesFullSearch
ON(r.Id = recipesFullSearch.[Key])";
string sql = string.Format(@"SELECT Id,Title FROM dbo.[Ingredients] WHERE Id = @id;
;WITH RowCounter AS (
SELECT COUNT(r.Id) as TotalRows
FROM
[dbo].[Recipes] r
INNER JOIN [dbo].[RecipeIngredients] RI ON RI.Recipe_Id = r.Id
INNER JOIN [dbo].[Ingredients] I ON RI.Ingredient_Id = I.Id
{0} -- inject search phrase here if not empty
WHERE
[Active] = 1 AND [Approved] = 1
AND I.Id = @Id
),
DataRows AS (
SELECT
r.Id
,STUFF( -- combine all tags into a 'csv list' like pepper[i:123]salt[i:124]...
(
SELECT TOP 3
']' + Title + '[i:' + CAST(Ingredient_Id AS nvarchar(11)) [text()]
FROM
(
SELECT
RI.Recipe_Id
,RI.Ingredient_Id
,I.Title
FROM dbo.RecipeIngredients AS RI
INNER JOIN dbo.Ingredients AS I
ON RI.Ingredient_Id = I.Id
-- here's the relation to the main query
WHERE RI.Recipe_Id = r.Id
) TempTable
FOR XML PATH(''), TYPE
).value('.','nvarchar(max)'),1,1,''
) IngredientsCSV
,r.Title
,LEFT(r.Description,260) as Description
,d.Title AS DishTypeTitle
,I.Title AS IngredientTitle
,RF.[file]
FROM
[dbo].[Recipes] r
INNER JOIN [dbo].[DishTypes] d ON r.DishType_Id = d.Id
INNER JOIN [dbo].[RecipeIngredients] RI ON RI.Recipe_Id = r.Id
INNER JOIN [dbo].[Ingredients] I ON RI.Ingredient_Id = I.Id
{0} -- inject search phrase here if not empty
OUTER APPLY
(SELECT TOP 1 recipe_id,[file] FROM dbo.RecipeFiles WHERE recipe_id = r.id ) RF
WHERE
[Active] = 1 AND [Approved] = 1 AND I.[Id] = @Id
ORDER BY
r.Id DESC
OFFSET (@PageNumber) ROWS
FETCH FIRST (@RowsPerPage) ROWS ONLY
)
SELECT
dr.*,
(select TotalRows from rowcounter) as TotalRows
FROM
DataRows dr;"
, !string.IsNullOrEmpty(q) ? searchSql : ""
);
using (SqlConnection conn = new("data source=someip;initial catalog=mydb;persist security info=True;user id=u;password=p"))
{
using (var data = await conn.QueryMultipleAsync(sql, new
{
SearchPhrase = q,
id,
PageNumber = (p - 1) * 8,
RowsPerPage = 8
}).ConfigureAwait(false))
{
return new RecipeListModel
{
Ingredient = await data.ReadSingleOrDefaultAsync<Ingredient>().ConfigureAwait(false),
Recipes = await data.ReadAsync<Recipe>().ConfigureAwait(false)
};
}
}
}
这是完整的事件日志(注意 NextResultAsync 而不是之前的 NextResult:
RequestPath: /ingredient/pepper-123
An unhandled exception has occurred while executing the request.
Exception: System.InvalidOperationException: Invalid attempt to call NextResultAsync when reader is closed. at Microsoft.Data.Common.ADP.ExceptionWithStackTrace(Exception e) --- End of stack trace from previous location --- at Dapper.SqlMapper.GridReader.NextResultAsync() in /_/Dapper/SqlMapper.GridReader.Async.cs:line 157 at Dapper.SqlMapper.GridReader.ReadBufferedAsync[T](Int32 index, Func
2 deserializer) in /_/Dapper/SqlMapper.GridReader.Async.cs:line 241 at myproject.Controllers.HomeController.GetRecipesByIngredientAsync(Int32 p, Int32 id, String title, String q) in C:\Web\myproject\myproject-net\Controllers\HomeController.cs:line 502 at myproject.Controllers.HomeController.Ingredient(String title, Int32 id, String q, Int32 page) in C:\Web\myproject\myproject-net\Controllers\HomeController.cs:line 125 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask
1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilder.<>c.<b__8_0>d.MoveNext() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at SixLabors.ImageSharp.Web.Middleware.ImageSharpMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context) at WebMarkupMin.AspNetCore2.WebMarkupMinMiddleware.ProcessAsync(HttpContext context, Boolean useMinification, Boolean useCompression) at WebMarkupMin.AspNetCore2.WebMarkupMinMiddlewareBase.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)
我不能肯定地说,但它似乎是 ReadSingleOrDefaultAsync
中的一个错误,导致它关闭连接。
我们的想法是在关闭连接之前完全读取所有结果集,因此您需要使用能够做到这一点的东西。这可能是 foreach
、ToList
、ToDictionary
或 SingleOrDefault
。
所以改用 ReadAsync
并将其输入标准 SingleOrDefault
。
model = new RecipeListModel
{
Ingredient = (await data.ReadAsync<Ingredient>().ConfigureAwait(false)).SingleOrDefault(),
Recipes = (await data.ReadAsync<Recipe>().ConfigureAwait(false)).ToList(),
}
我希望有机会调试 Dapper 源代码,并更新此答案以准确说明问题所在。