使用 LINQ 和谓词时,Entity Framework Core 不生成Where 子句

Kyl*_* L. 1 c# sql linq entity-framework-core .net-core

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

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

某个实体:

public class SomeEntity
{
    public string MyProp { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

数据库上下文:

public class ApplicationContext : DbContext
{
    public DbSet<SomeEntity> SomeEntities { get; set; }
    /* Rest of the DbContext doesn't matter. */
}
Run Code Online (Sandbox Code Playgroud)

道:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

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

public class SomeEntity
{
    public string MyProp { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

SELECT [e].MyProp 
FROM [TABLE_NAME] as [e]
Run Code Online (Sandbox Code Playgroud)

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

为什么?

Kyl*_* L. 5

问题在于您将Func<SomeEntity, bool>LINQ 的Where方法作为谓词传递。当您将 a 传递Func给它时Where,它会返回一个IEnumerable.

当您告诉 EF Core 返回一个IEnumerable信息时,您所传达的意思是您已完成数据集查询并想要枚举结果。因此,它会生成一个没有适当服务器端子WHERE句的查询,并立即提取所有数据。

不要Func在 DAO 类中接受 a 作为参数,而是接受 an Expression<Func<SomeEntity, bool>>,因为当您将 an 传递Expression给 LINQ 的Where方法时,它将返回一个IQueryable而不是一个IEnumerable。这有两件事:

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

所以而不是

public IEnumerable<SomeEntity> Where(Func<SomeEntity, bool> predicate)
{
    return _dbSet.Where(predicate);
}
Run Code Online (Sandbox Code Playgroud)

它应该是

public IEnumerable<SomeEntity> Where(Expression<Func<SomeEntity, bool>> predicate)
{
    return _dbSet.Where(predicate);
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

查询结果:

public IEnumerable<SomeEntity> Where(Func<SomeEntity, bool> predicate)
{
    return _dbSet.Where(predicate);
}
Run Code Online (Sandbox Code Playgroud)

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

我通过长时间浏览 SO 帖子找到了这个答案,并在阅读/sf/answers/2937366631/后终于找到了答案。由于原始问题与该问题无关,因此在此处重新发布一个与答案更一致的问题。