我想将IQueryable强制转换为这样的接口:
public static IQueryable<T> _enableFilter<T>(this IQueryable<T> queryable) => queryable.Where(x => (x as IEnable).Enable);
_newsRepository.BaseQuery.EnableFilter().FirstOrDefaultAsync(x => x.Id == model.Id);
它在EF core 2.2上工作,但在3中我给出了此错误:
System.InvalidOperationException : The LINQ expression 'Where<News>(
source: DbSet<News>,
predicate: (n) => (n as IEnable).Enable)' 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(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
答案 0 :(得分:3)
其背后的原因是EF Core 3处理此类情况的方式发生了变化。
在EF core 2.x中,它被拉到内存中并自动完成操作,由于这样做的潜在性能问题,EF核心团队决定将其从默认行为转变为错误。是默认行为。
本质上,如果您想要与2.x相同的行为,则现在必须在执行此操作之前将其显式拉入内存-但是,这通常可能表明它可能会更好地更改查询的执行方式-除非您确实确实需要这种行为
有关更改的更多详细信息,请参见Here
答案 1 :(得分:3)
该查询在EF Core 2.2中也不起作用。该类型转换在SQL中没有意义-SQL中没有接口或继承。 EF Core 3之前的版本具有...不幸的功能,即客户端评估。如果EF Core无法将某些内容转换为SQL,它将把所有内容都拉到客户端,并尝试在此过滤数据。不用说,这对于性能来说是灾难性的。更糟糕的是,它没有任何警告就这样做了。警告或异常将使您能够识别并解决问题。至少在EF Core 2.2中,可以禁用客户端评估。在EF Core 3中,这永远消失了。
对于方法本身,如果使用类型约束,则根本不需要进行强制转换,例如:
public static IQueryable<T> _enableFilter<T>(this IQueryable<T> queryable)
where T:IEnable
{
return queryable.Where(x => (x as IEnable).Enable);
}
我不确定EF Core是否会接受这一点-这是不寻常的语法。只需添加该额外条件,例如:
_newsRepository.BaseQuery.EnableFilter().FirstOrDefaultAsync(x => x.Id == model.Id && x.Enabled);
全局查询和软删除
如果要对使用特定实体的所有查询应用过滤条件(例如,实施软删除),则可以使用global filters。实际上,软删除是文档中提到的第一种情况。
在上下文的OnModelCreating()
方法中,您可以添加:
modelBuilder.Entity<SomeEntity>().HasQueryFilter(p => p.IsEnabled);