C# Dapper:在读卡器关闭时调用NextResult的尝试无效
在尝试使用.NET 5.0、Dapper 2.0.78和async和MSSQL Server执行多个语句时,有时会出现以下错误: System.InvalidOperationException:调用NextResult的尝试无效 当读卡器关闭时。在 Microsoft.Data.SqlClient.SqlDataReader.TryNextResult(布尔值和更多值)C# Dapper:在读卡器关闭时调用NextResult的尝试无效,c#,asp.net,sql-server,dapper,C#,Asp.net,Sql Server,Dapper,在尝试使用.NET 5.0、Dapper 2.0.78和async和MSSQL Server执行多个语句时,有时会出现以下错误: System.InvalidOperationException:调用NextResult的尝试无效 当读卡器关闭时。在 Microsoft.Data.SqlClient.SqlDataReader.TryNextResult(布尔值和更多值) 位于Microsoft.Data.SqlClient.SqlDataReader.NextResult()处 中的Dappe
位于Microsoft.Data.SqlClient.SqlDataReader.NextResult()处 中的Dapper.SqlMapper.GridReader.NextResult() //Dapper/SqlMapper.GridReader.cs:第414行 Dapper.SqlMapper.GridReader.ReadDeferred[T](Int32索引,Func 2 反序列化程序,类型为effectiveType)+System.IDisposable.Dispose(),位于 Dapper.SqlMapper.GridReader.ReadDeferred[T](Int32索引,Func 2 反序列化程序,在中键入effectiveType)+MoveNext() //Dapper/SqlMapper.GridReader.cs:at的第384行 System.Collections.Generic.List 1..ctor(IEnumerable 1集合)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) 这种情况并非总是发生。我怀疑SQL连接是无意中关闭的。有什么不对劲 为了调试,我测试了SQL语句,并查看了SSMS中的执行计划-这里没有标记任何内容,即正确的索引、配置了主键,它在很短的时间内执行。 SQL Server具有
- 16GB内存
- 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; }
// ...
}
专用异步任务GetRecipesByingRadientSync(int-id)
{
字符串sql=@“从dbo中选择Id和标题。[配料]其中Id=@Id;
从dbo中选择ID,Title。[Recipes]其中IngredientId=@ID;“//简化示例
RecipeListModel=new(){};
使用(SqlConnection conn=new(“此处为我的连接”))
{
var data=await conn.QueryMultipleAsync(sql,new{id}).ConfigureAwait(false);
模型=新的RecipeListModel
{
Component=data.ReadAsync().Result.SingleOrDefault(),
Recipes=data.ReadAsync().Result.ToList()
};
}
返回模型;//这里发生异常。
}
公共类成分
{
公共int Id{get;set;}
公共字符串标题{get;set;}
// ...
}
公共课食谱
{
公共int Id{get;set;}
公共字符串标题{get;set;}
// ...
}
公共类RecipeListModel
{
公共IEnumerable配方{get;set;}
公共成分成分{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)
};
}
}
}
[Route(“~/{lang}/component/{title}-{id}”,Name=“component view”)]
公共异步任务成分(字符串标题、int-id、字符串q、int-page=1)
{
if(ModelState.IsValid)
{
var模型=等待GetRecipesByingRadientSync(页面、id、标题、q)。配置等待(false);
如果(model.component==null | | Common.ClearUrl(model.component.Title)!=Title)//出于SEO目的,请确保我们没有篡改的URL
{
返回NotFound();
}
if(model.Recipes.Any())
{
var total=model.Recipes.First().TotalRows;
model.TotalRows=总计;
model.Pager=新的寻呼机(共8页);
model.q=string.IsNullOrEmpty(q)?“”:q.ToString();
返回视图(模型);
}
其他的
{
RecipeListModel empty=new()
{
配方=新列表(){new Recipe(){Title=”“}},
寻呼机=新寻呼机(0,0,1),
q=q
};
返回视图(空);
}
}
返回NotFound();
}
专用异步任务GetRecipesByingCredentSync(int p、int id、字符串标题、字符串q)
{
字符串searchSql=@”--可选(搜索短语可以为空)
将FREETEXTTABLE([dbo].[FT_Recipes_v],*,@SearchPhrase,语言'English')作为recipesFullSearch进行内部连接
ON(r.Id=recipesFullSearch.[Key])”;
string sql=string.Format(@“选择Id,来自dbo的标题。[配料]其中Id=@Id;
;以RowCounter作为(
选择计数(r.Id)作为总计行
从…起
[dbo].[Recipes]r
RI.Recipe_Id=r.Id上的内部联接[dbo].[RecipeIngElements]RI
RI.component\u Id=I.Id上的内部联接[dbo].[components]I
{0}--如果不是空的,则在此处插入搜索短语
哪里
[有效]=1和[已批准]=1
而I.Id=@Id
),
数据行作为(
挑选
r、 身份证
,STUFF(--将所有标签组合成一个“csv列表”,如胡椒[i:123]盐[i:124]。。。
(
选择前三名
']'+Title+'[i:'+CAST(成分Id为nvarchar(11))[text()]
从…起
(
挑选
RI.u\Id
,RI.u-Id
,即标题
来自dbo.RecipeI