【问题标题】:Entity Framework Core Not Generating Where Clause When Using LINQ and predicate [duplicate]使用 LINQ 和谓词时,实体框架核心未生成 Where 子句 [重复]
【发布时间】:2020-10-15 16:32:25
【问题描述】:

错误地标记为重复 - 请参阅下面的答案

基本设置 - 我有一个应用程序上下文和一个作为 DAO 构建的抽象:

某个实体:

public class SomeEntity
{
    public string MyProp { get; set; }
}

数据库上下文:

public class ApplicationContext : DbContext
{
    public DbSet<SomeEntity> SomeEntities { get; set; }
    /* Rest of the DbContext doesn't matter. */
}

道:

public class DAO
{
    private readonly DbSet<SomeEntity> _dbSet;

    public DAO(ApplicationContext context)
    {
        _dbSet = context.SomeEntities;
    }

    public IEnumerable<SomeEntity> Where(Func<SomeEntity, bool> predicate)
    {
        return _dbSet.Where(predicate);
    }
}

用法:

Dao dao = new Dao(/* whatever for instantiation */);
var results = dao.Where(e => e.MyProp == "my string");

预期行为: 我希望 EF Core 生成如下 SQL 查询:

SELECT [e].MyProp 
FROM [TABLE_NAME] AS [e]
WHERE [e].MyProp = 'my string'

实际行为: EF Core 生成以下 SQL 查询:

SELECT [e].MyProp 
FROM [TABLE_NAME] as [e]

它省略了 where 子句,导致应用程序在过滤之前将每条记录拉入内存。

为什么?

【问题讨论】:

  • @GSerg - 是的 - 它是相关的!感谢您的参考,希望我能在两天前找到它!
  • 停止将其标记为要关闭或重复的内容 - 搜索“EF Core Missing Where Clause”时不会弹出其他问题,这是为了能够搜索而不是一些EF Core 深处的晦涩问题。
  • 这个话题并不新鲜,已经讨论过很多次了,还有floating point mathsql injections。我个人认为它不值得一个新的单独的自我回答问题,你认为否则,没问题。你自己说另一个问题涵盖了这个问题,这足以成为同意近距离投票的理由。 [...]
  • [...] 我们在这里love duplicates。关闭一个重复的问题不是惩罚。问题本身不会被删除,并且可以很好地增加关键字的种类,使用这些关键字可以找到原始内容。
  • 此问题并非特定于 EF Core,它一直存在于 since Linq2Sql 周围。我选择了这个特定的问题,因为它本身就是另外两个问题的重复,方便地放在它的顶部:stackoverflow.com/q/793571/11683stackoverflow.com/q/252785/11683,这很好地将您带到stackoverflow.com/a/34606818/11683

标签: c# sql linq .net-core entity-framework-core


【解决方案1】:

问题在于您将Func&lt;SomeEntity, bool&gt; 作为谓词传递给LINQ 的Where 方法。当您将Func 传递给Where 时,它会返回IEnumerable

当您告诉 EF Core 返回 IEnumerable 时,您的意思是您已完成对数据集的查询并希望枚举结果。因此,它会在没有适当的服务器端 WHERE 子句的情况下生成一个查询,并一次提取所有数据。

不要接受Func 作为DAO 类中的参数,而是接受Expression&lt;Func&lt;SomeEntity, bool&gt;&gt;,因为当您将Expression 传递给LINQ 的Where 方法时,它将返回IQueryable 而不是IEnumerable .这做了两件事:

  1. 允许您在执行前向查询添加其他操作。
  2. 告诉 EF Core 您要在将结果集返回到应用程序之前过滤 SQL 中的记录。

所以不是

public IEnumerable<SomeEntity> Where(Func<SomeEntity, bool> predicate)
{
    return _dbSet.Where(predicate);
}

应该是

public IEnumerable<SomeEntity> Where(Expression<Func<SomeEntity, bool>> predicate)
{
    return _dbSet.Where(predicate);
}

用法:

Dao dao = new Dao(/* whatever for instantiation */);
var results = dao.Where(e => e.MyProp == "my string");

结果查询:

SELECT [e].MyProp 
FROM [TABLE_NAME] as [e]
WHERE [e].MyProp = 'my string'

注意该方法的实现实际上并没有改变,用法也没有改变 - 这是因为 FuncExpression 的某些形式是可以互换的,在这种情况下使用其中一种或另一种会导致没有编译错误,因此基本相同。

我通过数小时浏览 SO 帖子找到了这个答案,并在阅读 https://stackoverflow.com/a/41962380/2573572 后终于找到了答案。在此处重新发布一个与答案更一致的问题,因为原始问题与该问题无关。

【讨论】:

  • 如果您刚刚查看了Queryble.Where(和其他Queryable)扩展方法的签名,您可以更快地找到答案。 Expression&lt;Func&lt;...&gt;&gt;Func&lt;...&gt;QueryableEnumerable LINQ 查询之间的根本区别。
  • 对于不轻易投资于 .NET-isms 的人来说,返回 IQueryable 与 IEnumerable 的事实不足以让人们将其与不构建 SQL 查询联系起来。感谢您的意见。
猜你喜欢
  • 1970-01-01
  • 2021-04-09
  • 2014-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-19
  • 2011-12-31
相关资源
最近更新 更多