在循环中使用 LINQ Entity Framework 表达式中的变量获取最后一个值
Using variables in LINQ Entity Framework expression inside a loop gets the last value
我正在尝试使用 C# Entity framework LINQ 创建一个 SQL 查询,它会产生类似的 SQL ,如下所示:
select * from centros
where SUBSTRING(UPPER(c_nombre),1,1)='M'
and (SUBSTRING(UPPER(c_nombre),2,1)='A' OR SUBSTRING(UPPER(c_nombre),2,1)='Á')
and SUBSTRING(UPPER(c_nombre),3,1)='L'
order by c_nombre
limit 10
这是我的代码:
public List<Entidad> SearchByDescServer(string desc, int limit)
{
List<Entidad> entidades = new List<Entidad>();
IQueryable<IEntidad> models = entitySet.AsNoTracking();
for (int index = 0; index < desc.Length; index++) {
string currentChar = desc.Substring(index,1).ToUpper();
models = models.Where(e=>e.Descripcion.Substring(index,1).ToUpper()==currentChar);
}
models = models.OrderBy(e => e.Descripcion).Take(limit);
foreach (IEntidad m in models.ToList()) {
entidades.Add(m.ToEntidad());
}
return entidades;
}
事情很简单,我在循环中向 IQueryable 对象添加 where 子句。我正在使用 PostgreSQL 数据库。调试告诉我这个:
Executed DbCommand (12ms) [
Parameters=[
@__8__locals1_index_0='3',
@__currentChar_1='A' (Size = 150),
@__8__locals1_index_2='3',
@__currentChar_3='A' (Size = 150),
@__8__locals1_index_4='3',
@__currentChar_5='A' (Size = 150),
@__p_6='10'
], CommandType='Text', CommandTimeout='30']
SELECT e.c_id, e.c_activo, e.c_codigo, e.c_nombre
FROM centros AS e
WHERE ((UPPER(SUBSTRING(e.c_nombre, @__8__locals1_index_0 + 1, 1)) = @__currentChar_1) AND (UPPER(SUBSTRING(e.c_nombre, @__8__locals1_index_2 + 1, 1)) = @__currentChar_3)) AND (UPPER(SUBSTRING(e.c_nombre, @__8__locals1_index_4 + 1, 1)) = @__currentChar_5)
ORDER BY e.c_nombre
LIMIT @__p_6
所以发生的事情是索引参数始终是循环后索引变量的最后一个值。谁能给我解释一下这种行为??
谢谢
引入临时变量并在lambda中使用它:
for (int index = 0; index < desc.Length; index++)
{
var tmp = index;
string currentChar = desc.Substring(index, 1).ToUpper();
models = models.Where(e=>e.Descripcion.Substring(tmp, 1).ToUpper()==currentChar);
}
至于原因 - 这就是 C# 闭包在 for 循环中的工作方式。简而言之 - 对于您的匿名函数 e=>e.Descripcion.Substring(i, 1).ToUpper()==currentChar
编译器生成特殊的 class 它将保存捕获的 i
变量,该变量将从索引的第一个值更新到最后一个值:
var actions = new List<Action>();
for (int i = 0; i < 10; i++)
{
actions.Add(() => Console.WriteLine(i));
}
// will print 10 times "10"
foreach (var a in actions)
{
a();
}
请记住 foreach
循环的行为不同:
var actions = new List<Action>();
foreach (var i in Enumerable.Range(0, 10))
{
actions.Add(() => Console.WriteLine(i));
}
// prints from 0 to 9
foreach (var a in actions)
{
a();
}
有关详细信息,您可以阅读这篇 answer by Jon Skeet and/or this 文章。
我正在尝试使用 C# Entity framework LINQ 创建一个 SQL 查询,它会产生类似的 SQL ,如下所示:
select * from centros
where SUBSTRING(UPPER(c_nombre),1,1)='M'
and (SUBSTRING(UPPER(c_nombre),2,1)='A' OR SUBSTRING(UPPER(c_nombre),2,1)='Á')
and SUBSTRING(UPPER(c_nombre),3,1)='L'
order by c_nombre
limit 10
这是我的代码:
public List<Entidad> SearchByDescServer(string desc, int limit)
{
List<Entidad> entidades = new List<Entidad>();
IQueryable<IEntidad> models = entitySet.AsNoTracking();
for (int index = 0; index < desc.Length; index++) {
string currentChar = desc.Substring(index,1).ToUpper();
models = models.Where(e=>e.Descripcion.Substring(index,1).ToUpper()==currentChar);
}
models = models.OrderBy(e => e.Descripcion).Take(limit);
foreach (IEntidad m in models.ToList()) {
entidades.Add(m.ToEntidad());
}
return entidades;
}
事情很简单,我在循环中向 IQueryable 对象添加 where 子句。我正在使用 PostgreSQL 数据库。调试告诉我这个:
Executed DbCommand (12ms) [
Parameters=[
@__8__locals1_index_0='3',
@__currentChar_1='A' (Size = 150),
@__8__locals1_index_2='3',
@__currentChar_3='A' (Size = 150),
@__8__locals1_index_4='3',
@__currentChar_5='A' (Size = 150),
@__p_6='10'
], CommandType='Text', CommandTimeout='30']
SELECT e.c_id, e.c_activo, e.c_codigo, e.c_nombre
FROM centros AS e
WHERE ((UPPER(SUBSTRING(e.c_nombre, @__8__locals1_index_0 + 1, 1)) = @__currentChar_1) AND (UPPER(SUBSTRING(e.c_nombre, @__8__locals1_index_2 + 1, 1)) = @__currentChar_3)) AND (UPPER(SUBSTRING(e.c_nombre, @__8__locals1_index_4 + 1, 1)) = @__currentChar_5)
ORDER BY e.c_nombre
LIMIT @__p_6
所以发生的事情是索引参数始终是循环后索引变量的最后一个值。谁能给我解释一下这种行为??
谢谢
引入临时变量并在lambda中使用它:
for (int index = 0; index < desc.Length; index++)
{
var tmp = index;
string currentChar = desc.Substring(index, 1).ToUpper();
models = models.Where(e=>e.Descripcion.Substring(tmp, 1).ToUpper()==currentChar);
}
至于原因 - 这就是 C# 闭包在 for 循环中的工作方式。简而言之 - 对于您的匿名函数 e=>e.Descripcion.Substring(i, 1).ToUpper()==currentChar
编译器生成特殊的 class 它将保存捕获的 i
变量,该变量将从索引的第一个值更新到最后一个值:
var actions = new List<Action>();
for (int i = 0; i < 10; i++)
{
actions.Add(() => Console.WriteLine(i));
}
// will print 10 times "10"
foreach (var a in actions)
{
a();
}
请记住 foreach
循环的行为不同:
var actions = new List<Action>();
foreach (var i in Enumerable.Range(0, 10))
{
actions.Add(() => Console.WriteLine(i));
}
// prints from 0 to 9
foreach (var a in actions)
{
a();
}
有关详细信息,您可以阅读这篇 answer by Jon Skeet and/or this 文章。