C# Can';t在EF Where表达式中为lambda属性使用LINQ

C# Can';t在EF Where表达式中为lambda属性使用LINQ,c#,.net-core,.net-core-3.0,C#,.net Core,.net Core 3.0,我这样改变了LINQ的表情 public async Task<IEnumerable<Thing>> Get(bool all) { List<Thing> output = await Context.Things //.Where(_ => all || _.DeletedOn == null && _.Deletedon < DateTime.Now) .Where(_ => all || _.Ac

我这样改变了LINQ的表情

public async Task<IEnumerable<Thing>> Get(bool all)
{
  List<Thing> output = await Context.Things
    //.Where(_ => all || _.DeletedOn == null && _.Deletedon < DateTime.Now)
    .Where(_ => all || _.Active)
    .ToListAsync();
  return output;
}
class Thing
{
  ...
  public DateTime? DeletedOn { get; set; }
  public Active => DeletedOn == null && DeletedOn < DateTime.Now.
}
公共异步任务Get(bool all)
{
列表输出=等待上下文
//.Where(|=>all | | |.DeletedOn==null&&.DeletedOnall | | 124;.Active)
.ToListAsync();
返回输出;
}
显然,它导致了以下错误

InvalidOperationException:无法翻译LINQ表达式“DbSet.Where(l=>False | | l.Active)”。以可以翻译的形式重写查询,或者通过插入对AsEnumerable()、AsAsAsAsyncEnumerable()、ToList()或ToListSync()的调用显式切换到客户端计算

嗯,我确实调用了AsListAsync(),我有点激动,因为这样一个简单的条件不能被.NET核心EF解释。我想我可能错过了别的东西

课堂上的事情是这样的

public async Task<IEnumerable<Thing>> Get(bool all)
{
  List<Thing> output = await Context.Things
    //.Where(_ => all || _.DeletedOn == null && _.Deletedon < DateTime.Now)
    .Where(_ => all || _.Active)
    .ToListAsync();
  return output;
}
class Thing
{
  ...
  public DateTime? DeletedOn { get; set; }
  public Active => DeletedOn == null && DeletedOn < DateTime.Now.
}
类的东西
{
...
公共日期时间?DeletedOn{get;set;}
public Active=>DeletedOn==null&&DeletedOn
检查数据库时什么也没给我。

请参阅

一种解决方案(尽管未建议)可以是:

如果查询无法完全翻译,则可以将查询重写为可以翻译的形式,或者使用AsEnumerable()、ToList()或类似方法将数据显式带回客户端,然后使用LINQ to对象对其进行进一步处理

因此,就像以前一样,使用可翻译查询获取dbset,并在以后使用您喜欢的任何C#linq to Objects magic进行过滤

如果没有测试,我相信EF无法翻译您的。当你尝试以下方法时,它起作用了吗

   .Where(_ => all || _.DeletedOn == null && _.Deletedon < DateTime.Now) 
.Where(=>all | | |.DeletedOn==null&&.DeletedOn
问题在于公共字段中的表达式主体处于活动状态。
EF无法翻译此表达式
Active=>DeletedOn==null&&DeletedOn

正如其他人所提到的,表达式体成员
getter
实际上被认为是一个方法调用,它由Linq查询提供程序转换为本机SQL,因此,您需要再次撤消“干”代码,而是将
Active
属性中的谓词逻辑直接扩展到Linq查询中,或者您需要将整个表达式树或IQueryable传递给类似
Active
的方法,以便将谓词组合到其中(这似乎有些过分)

另外,根据注释,有一个逻辑问题-
.DeletedOn==null&&.DeletedOn
将返回false,这意味着根据
all
参数的值,查询是全部还是无。猜测一下,您正在寻找一个有条件应用的“逻辑删除”筛选器,该筛选器还允许将来的日期删除,即,任何尚未删除的记录都将被视为活动记录,或者任何具有空删除日期的记录都没有被删除

最后,对于大多数RDBMS,尤其是SQL Server,将硬编码谓词(如
all
)添加到
WHERE
过滤器中通常不是一个好主意,因为这可能会弄乱。在您的情况下,
all
标记过滤逻辑仅决定是否要在逻辑上包含
Deleted
数据。在我看来,为了避免在SQL中进行不必要的过滤,我希望如下所示

综上所述,问题是:

var query = Context.Things;
if (!all)
{
   query = query.Where(t => t.DeletedOn == null || t.Deletedon > DateTime.Now)
}
var output = await query
   .ToListAsync();
return output;

在筛选记录之前,请尝试插入对AsEnumerable()、AsAsAsAsyncEnumerable()、ToList()或ToListSync()的调用,例如,在本例中,在Where条件之前。由于条件Active=>DeletedOn==null&&DeletedOnWhere(=>allEF在使用计算属性时有限制,因为很难找到它们后面的“位置”。它基本上尝试映射属性名称(即活动)到数据库列,这将失败并导致错误。简而言之,我认为您必须坚持使用第一个选项。它怎么可以同时为null和小于现在的值?至于您的错误消息,linq无法转换您的bool Active属性,因为它不是一个表达式。
的SQL是什么。Where(\u=>all)
@ShahidManzoorBhat我猜
1=1
如果
all=true
@ShahidManzoorBhat它将返回所有元素,无论它们是否被软删除。在SQL:select*中,即无where条件。这是一个真正的问题。我理解其背后的原理。尽管如此,我还是更愿意让我在p中使用我的东西潜在的昂贵方式。在许多情况下,DRY在性能上没有或几乎没有提高。我不喜欢。但是对于链接和信息点+1。根据惯例,OP不应该使用
\uuuuu
作为已使用的lambda参数,因为它在许多FP语言中重新调整用途以指示参数。您应该将注释移动到yo的一部分你的回答。我完全不知道这个约定(伟大的链接顺便说一句),因为缺乏想象力而使用下划线。下划线是新的黑色(即变量命名)或者我是这么想的……是的。最不令人惊讶的原则是——确保下一个家伙能用最少的白发阅读你的代码。我发现迄今为止最好的惯例是Sql表别名——实体名称的第一个字母,因此表示事物。那么……关于逻辑删除逻辑……啊,你是说“bug”人们发现了吗?在实际代码中,它实际上是由几个条件组成的更复杂的表达式(所有条件都与删除、创建和最新更改的日期有关。我在尝试排除故障时将其缩短,但没有注意到我引入了一个“bug”.你指的是什么?哦,我刚刚意识到lambda表达式中第一个字母的约定有两个奇怪的地方。