如何使用LINQ实现条件惰性加载

3

我是LINQ的新手

我正在尝试使用延迟加载执行动态 where,但我不明白该如何做。

这是我的代码

protected int AnimalCount(System.Func<Animal, bool> expression = null, System.Func<Animal, bool> additionalExpression= null)
    {
    var records = (from temp in DbContext.Animal select temp);
    if (expression != null) records = records.Where(expression).AsQueryable();
    if (additionalExpression != null) records = records.Where(additionalExpression).AsQueryable();
    return records.Count();
}

现在的问题是查询非常缓慢,我认为这是因为where子句被应用于查询的SELECT * FROM Animal列表上。


可能实际上是数据库的问题,比如不正确或缺失的索引。您传递了什么表达式导致它变慢? - Matt U
为什么不将您的签名更改为 protected int AnimalCount(params System.Func<Animal, bool>[] expressions)?然后您可以使用循环来应用它们。 - Igor
不是直接关于你的问题,但是 AsQueryable() 在那里是无用的。 - Mat J
顺便提一下,“惰性加载”一词是指在需要时按需加载,而不是预先加载。EF支持使用属性进行此操作,但我更喜欢不使用它。这个术语在这里不适用,因为您想要将可变数量的表达式应用于查询。我只是这样说,这样您就可以使用正确的术语,这在传达有关主题的问题/信息时非常重要。 - Igor
@Igor,感谢您对术语的纠正。 - limdev
2个回答

7
  • 您应该使用 System.Linq.Expression<System.Func<Animal, bool>> 而不是 System.Func<Animal, bool>,这是与 EF 一起使用所必需的,我假设您希望表达式作为 SQL 应用而非在内存中。
  • 您可以更改签名以使用 params 和表达式数组,然后迭代它们来应用它们。

更改后的代码:

protected int AnimalCount(params System.Linq.Expression<System.Func<Animal, bool>>[] expressions)
{
    var records = DbContext.Animal as IQueryable<Animal>;
    foreach (var expression in expressions)
      records = records.Where(expression);
    return records.Count();
}

0

Linq to Entity会构建表达式树,当你请求实际数据时,它会将你的请求应用于数据库并返回结果。因此,默认情况下是延迟加载。

var request = DbContext.Animal.AsQeriable();

if (predicate != null) 
    request = request.Where(predicate);

return request.Count();

你也可以接受谓词数组作为参数,如下所示: Foo(params Expression<Func<Animal, bool>>[] predicates) 然后在函数内部使用它们,像这样:
foreach(var predicate in predicates) 
      request = request.Where(predicate);

1
完全不起作用。EF需要将表达式转换为SQL。然而,OP提供的是函数,而不是表达式。EF无法猜测这些函数背后的代码,因此必须要么加载所有内容到内存中,要么抛出异常。EF和EF Core 3.0会抛出异常。EF Core 1.0-2.x会将所有内容加载到内存中,这是一个不幸的决定。 - Panagiotis Kanavos
1
我是指Expression<Func<Animal, bool>>[]谓词,并已在我的答案中进行了修正。对于误解,我很抱歉。 - Gleb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接