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

14 浏览
0 Comments

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

错误标记的重复 - 请参见下面的答案

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

SomeEntity:

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

DbContext:

public class ApplicationContext : DbContext
{
    public DbSet SomeEntities { get; set; }
    /* 其他DbContext不重要。 */
}

DAO:

public class DAO
{
    private readonly DbSet _dbSet;
    public DAO(ApplicationContext context)
    {
        _dbSet = context.SomeEntities;
    }
    public IEnumerable Where(Func predicate)
    {
        return _dbSet.Where(predicate);
    }
}

用法:

Dao dao = new Dao(/* 实例化所需的任何参数 */);
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子句,导致应用程序在筛选之前将所有记录都加载到内存中。

为什么?

0
0 Comments

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

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

在DAO类中,不要接受Func作为参数,而是接受Expression<Func<SomeEntity, bool>>,因为当您将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是可以互换的,在这种情况下使用其中一个或另一个不会导致编译错误,因此在本质上是相同的。

我通过查看Queryble.Where(和其他Queryable)扩展方法的签名找到了这个答案。 Expression<Func<...>>Func<...>之间的基本区别是QueryableEnumerable LINQ查询之间的区别。

对于那些不熟悉.NET的人来说,返回一个IQueryable与返回一个IEnumerable的事实并不足以让人们将其与不构建SQL查询联系起来。感谢您的参与。

0