英文:
There is already an open DataReader associated with this Connection which must be closed first in rawsql sentences
问题
context.Database.ExecuteSql引发了标题异常。
我应该如何在.NET Core中使用原始SQL检索数据集并进行处理?
英文:
context.Database.ExecuteSql raise the title exception.
How must I use raw sql in .net core to retrieve a dataset and process it like ?
public async Task<IActionResult> Refresh_Formatos()
{
using (var context = _context)
{
var padre = context.Database.SqlQuery<int>(
$@"SELECT id
FROM pds_etiquetas where nombre='FORMATOS' and tipo = 'Cat'
").ToList();
int padre_id = padre[0];
var formatos = context.Database.SqlQuery<string>(
$@"SELECT xdescripcion
FROM vc00_formatos a
left join pds_etiquetas c on a.xdescripcion=c.Nombre and {padre_id}=c.PadreId and c.tipo = 'Val'
where c.id is null
order by xdescripcion");
context.Database.CloseConnection();
foreach (var formato in formatos)
{
var affectedRows = context.Database.ExecuteSql(
$@"INSERT INTO [imp].[pds_etiquetas]
([Nombre]
,[Tipo]
,[PadreId])
VALUES
('{formato}'
,'Val'
,{padre_id})
");
}
}
return Ok();
}
答案1
得分: 2
SqlQuery 返回一个 IEnumerable,当它被枚举时会执行查询。在关闭连接之后枚举它,所以它尝试在关闭连接后执行查询。
在关闭连接之前使用 ToList() 应该可以解决这个问题,因为它会在调用时枚举它。即:
var formatos = context.Database.SqlQuery<string>(
$@"SELECT xdescripcion
FROM vc00_formatos a
left join pds_etiquetas c on a.xdescripcion=c.Nombre and {padre_id}=c.PadreId and c.tipo = 'Val'
where c.id is null
order by xdescripcion").ToList();
context.Database.CloseConnection();
更多信息请参考:Microsoft 文档。
英文:
SqlQuery returns an IEnumerable that will execute the query when it is enumerated. You are enumerating it after you have closed the connection, so it is trying to execute the query after closing the connection.
Using ToList() before you close the connection should fix it as it will enumerate it when that is called. I.e.:
var formatos = context.Database.SqlQuery<string>(
$@"SELECT xdescripcion
FROM vc00_formatos a
left join pds_etiquetas c on a.xdescripcion=c.Nombre and {padre_id}=c.PadreId and c.tipo = 'Val'
where c.id is null
order by xdescripcion").ToList();
context.Database.CloseConnection();
答案2
得分: 1
你需要将formatos
放入一个List
中。
- 您还应该正确参数化您的查询。
- 您应该使用
Async
函数,但似乎旧的 EF 不提供SqlQueryAsync
。
public async Task<IActionResult> Refresh_Formatos()
{
using (var context = _context)
{
var padre_id = context.Database.SqlQuery<int>(
@"
SELECT id
FROM pds_etiquetas
where nombre = 'FORMATOS'
and tipo = 'Cat'
").First();
var formatos = context.Database.SqlQuery<string>(
@"
SELECT xdescripcion
FROM vc00_formatos a
left join pds_etiquetas c on a.xdescripcion=c.Nombre and @padre_id = c.PadreId and c.tipo = 'Val'
where c.id is null
order by xdescripcion",
new SqlParameter("@padre_id", SqlDbType.Int) { Value = padre_id }
).ToList();
foreach (var formato in formatos)
{
var affectedRows = await context.Database.ExecuteSqlAsync(
@"
INSERT INTO imp.pds_etiquetas
(Nombr, Tipo, PadreId)
VALUES (@formato, 'Val', @padre_id)
",
new SqlParameter("@padre_id", SqlDbType.Int) { Value = padre_id },
new SqlParameter("@formato", SqlDbType.VarChar, 250) { Value = formato }
);
}
}
return Ok();
}
话虽如此,您不需要做任何这些,您可以只执行一个大的联接INSERT
。
您还可以将LEFT JOIN
更改为NOT EXISTS
,并且应该使用新的上下文而不是现有的一个。
public async Task<IActionResult> Refresh_Formatos()
{
using var context = new YourContextHere();
var affectedRows = await context.Database.ExecuteSqlAsync(@"
INSERT INTO imp.pds_etiquetas
(Nombr, Tipo, PadreId)
SELECT
a.xdescripcion,
'Val',
p.id
FROM pds_etiquetas p
CROSS JOIN vc00_formatos a
where p.nombre = 'FORMATOS'
and p.tipo = 'Cat'
AND NOT EXISTS (SELECT 1
FROM pds_etiquetas c
WHERE a.xdescripcion = c.Nombre
and p.id = c.PadreId
and c.tipo = 'Val'
);
");
return Ok();
}
英文:
You need to put formatos
into a List
- You should also parameterize your queries properly
- You should use
Async
functions, but it appears the old EF does not provideSqlQueryAsync
.
public async Task<IActionResult> Refresh_Formatos()
{
using (var context = _context)
{
var padre_id = context.Database.SqlQuery<int>(
@"SELECT id
FROM pds_etiquetas
where nombre = 'FORMATOS'
and tipo = 'Cat'
").First();
var formatos = context.Database.SqlQuery<string>(
@"SELECT xdescripcion
FROM vc00_formatos a
left join pds_etiquetas c on a.xdescripcion=c.Nombre and @padre_id = c.PadreId and c.tipo = 'Val'
where c.id is null
order by xdescripcion",
new SqlParameter("@padre_id", SqlDbType.Int) { Value = padre_id }
).ToList();
foreach (var formato in formatos)
{
var affectedRows = await context.Database.ExecuteSqlAsync(
@"INSERT INTO imp.pds_etiquetas
(Nombr, Tipo, PadreId)
VALUES (@formato, 'Val', @padre_id)
",
new SqlParameter("@padre_id", SqlDbType.Int) { Value = padre_id },
new SqlParameter("@formato", SqlDbType.VarChar, 250) { Value = formato }
);
}
}
return Ok();
}
Having said that, you don't need to do any of this, you can just do one big joined INSERT
.
You can also change the LEFT JOIN
to a NOT EXISTS
, and you should use a new context rather than an existing one.
public async Task<IActionResult> Refresh_Formatos()
{
using var context = new YourContextHere();
var affectedRows = await context.Database.ExecuteSqlAsync(@"
INSERT INTO imp.pds_etiquetas
(Nombr, Tipo, PadreId)
SELECT
a.xdescripcion,
'Val',
p.id
FROM pds_etiquetas p
CROSS JOIN vc00_formatos a
where p.nombre = 'FORMATOS'
and P.tipo = 'Cat'
AND NOT EXISTS (SELECT 1
FROM pds_etiquetas c
WHERE a.xdescripcion = c.Nombre
and p.id = c.PadreId
and c.tipo = 'Val'
);
");
return Ok();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论