C# 为什么;LINQ表达式';x';无法翻译?I';我没有使用;其中();
当我执行以下代码时,我得到一个错误: System.InvalidOperationException:LINQ表达式'DbSet.Where(u=>u.NormalizedEmail==\u\u ToLower\u 0&& u、 无法翻译PasswordHash.SequenceEqual(_pass_1))' 但它在.NETCore2.2中运行良好。在.NET Core 3.1中出现错误C# 为什么;LINQ表达式';x';无法翻译?I';我没有使用;其中();,c#,linq,entity-framework-core,C#,Linq,Entity Framework Core,当我执行以下代码时,我得到一个错误: System.InvalidOperationException:LINQ表达式'DbSet.Where(u=>u.NormalizedEmail==\u\u ToLower\u 0&& u、 无法翻译PasswordHash.SequenceEqual(_pass_1))' 但它在.NETCore2.2中运行良好。在.NET Core 3.1中出现错误 loginCreds.Password = loginCreds.Password.ToLower();
loginCreds.Password = loginCreds.Password.ToLower();
var pass = Helper.ComputeHash(loginCreds.Password);
var usr = await _context.Users
.FirstOrDefaultAsync(u => u.NormalizedEmail == loginCreds.Email
&& u.PasswordHash.SequenceEqual(pass));
但是,当我将u.PasswordHash.SequenceEqual(pass)
替换为u.PasswordHash==新字节[16]
(仅用于测试)时,它可以工作。所以,问题在于SequenceEqual(byte[]byte)
方法
我怎样才能解决这个问题
任何评论都将不胜感激。在3.0之前,EF Core无法翻译的表达式将导致所有内容都被拉入客户端,然后在客户端进行过滤,这可能会变得非常缓慢。在3.0中,EF Core现在抛出一个异常,该异常的目标是开发人员优化他们的查询 因此,您的错误意味着EF Core无法将
u.PasswordHash.SequenceEqual(pass)
转换为SQL。您应该找到另一种方法来过滤查询
EF Core转换为SQL的方法有限(例如
string.StartsWith()
,list.Contains()
)。您可以在“受限客户端评估”中找到答案
例如,如果EF Core 2.2无法在
Where()调用时,它执行一个不带筛选器的SQL语句,
传输数据库中的所有行,然后对其进行筛选
记忆中
在EF Core 3.0中,我们将客户评估限制为仅在
顶层投影(本质上是对Select()的最后一次调用)。
当EF Core 3.0检测到无法在任何地方翻译的表达式时
否则在查询中,它会引发运行时异常
在EF Core 2.2中,带有SequenceEqual
的查询部分实际上不是在SQL中完成的
您应该尝试这样做:
var usr = await _context.Users
.Where(u => u.NormalizedEmail == loginCreds.Email)
.ToListAsync()
.FirstOrDefault(u => u.PasswordHash.SequenceEqual(pass));
您说过它在
dotnetcore2.2
中工作,但在dotnetcore3.1
中不工作。我假设这意味着您在dotnetcore3.1
版本中也使用了entityframeworkcore3
,看起来这是entityframeworkcore3
中的一个突破性变化
旧行为
在3.0之前,当EF Core无法将作为查询一部分的表达式转换为SQL或参数时,它会自动在客户端计算表达式。默认情况下,对潜在昂贵表达式的客户端计算只会触发警告
新行为
从3.0开始,EF Core只允许在客户机上计算顶级投影(查询中的最后一个Select()调用)中的表达式。当查询的任何其他部分中的表达式无法转换为SQL或参数时,将引发异常
SequenceEqual
无法转换为SQL或参数,因此在版本2.2
中,它会在客户端上自动执行该操作。现在在3.1
版本中,它抛出了一个invalidoOperationException
。使用相等运算符是可行的,因为它可以转换为SQL语句
为了修复它,为什么不选择“通过电子邮件”
然后比较密码
loginCreds.Password = loginCreds.Password.ToLower();
var pass = Helper.ComputeHash(loginCreds.Password);
var usr = await _context.Users
.FirstOrDefaultAsync(u =>u.NormalizedEmail == loginCreds.Email));
bool validUser = false;
if (usr != null)
{
validUser = usr.PasswordHash.SequenceEquals(pass);
}
// if validUser is true, then the credentials were valid.
你的用户对象是什么样子的?“我如何解决这个问题?”你已经解决了。使用
=
而不是SequenceEquals
。您的查询将被转换为SQL并执行。数据库不需要特殊的运算符来比较二进制数据。