我以前进行了以下设置:
public static bool BlogIsLive(BlogPost b)
{
return b.Status == (int)ItemStatus.Active && b.PublishDate < DateTime.Now ;
}
/// Database query
var blogs = (from b in db.BlogPost
where BlogIsLive(b) // <--- super useful, used in multiple places
select b
).ToList()
但是更新到EF Core 3.0之后,它会引发以下错误
/// The LINQ expression ... could not be translated. Either rewrite the query in a form
/// that can be translated, or switch to client evaluation explicitly by inserting a
/// call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
我了解这是EF Core 3.0重大更改的一部分
现在,我必须在BlogsIsLive()
之前的所有位置手动编写查询。
var blogs = from b in db.BlogPost
where b.Status == (int)ItemStatus.Active //<--- Annoying repetition of code
&& b.PublishDate < DateTime.Now //<---
select b
这很烦人。我无法写出插入其中的方法吗?
我知道EF具有DbFunctions,例如,它可以简化比较Date
值的过程,因此我看不出为什么无法编写自己的类似{{1 }},Int
或string
。
类似:
bool
我已经尝试了以上几种方法,但是没有运气。
谢谢。
答案 0 :(得分:2)
原始代码有一个严重的错误,该错误也可能会在任何非核心版本的EF中引发-它是一个本地函数,不能转换为SQL。 Where
接受表达式作为参数,而不是函数。无论如何,您不需要该功能。
LINQ与IQueryable和表达式一起使用。每个运算符采用一个IQueryable,然后返回另一个。 Where
和Select
就是这样工作的。这意味着您可以创建自己的函数来添加所需的Where
条件:
public static IQueryable<BlogPost> WhereActive(this IQueryable<BlogPost> query)
{
return query.Where(b=>b.Status == (int)ItemStatus.Active && b.PublishDate < DateTime.Now);
}
并与任何IQueryable<BlogPost>
一起使用,例如:
var finalQuery = query.WhereActive();
var posts=finalQuery.ToList();
另一个更麻烦的选择是在代码中构造Expression<Func<>>
调用,并将其传递给Where
-本质上是动态创建WHERE条件。在这种情况下,虽然不需要。
EF Core 1.0添加了一个非常不幸的功能(更像what-were-they-thinking!
这种功能),客户端评估。如果某些内容无法翻译,只需将所有内容加载到内存中,然后尝试过滤内容,而无需使用索引,执行计划,匹配算法,RAM和CPU在数据库服务器中找到的好处。
如果一次仅由一个客户端一次加载仅100行,这可能不会引起注意,这对于具有少量数据和并发用户的任何应用程序都是一种杀手f。
在Web应用程序中,这将转换为更多服务器以处理相同的流量。
这就是为什么在2008年EF 1.0推出时取消了客户端评估的原因。
答案 1 :(得分:1)
您可以使用已经具有该过滤器的DbSet,而不是使用db.BlogPost
作为查询的基础。
DbSet<BlogPost> _allBlogs {get;set;}
IQueryable<BlogPost> ActiveBlogs { get => _allBlogs.Where(b=> b.Status == (int)ItemStatus.Active); }
var blogs = from b in db.ActiveBlogs
select b