Ef core 3 铸件无法翻译
Ef core 3 casting could not be translated
我想将我的 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 核心 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.
这背后的原因是 EF Core 3 处理此类情况的方式发生了变化。
在 EF 核心 2.x 中,它被拉入内存并在那里自动完成操作,由于这样做的潜在性能问题,EF 核心团队决定将其从默认设置中移除错误行为是默认行为。
本质上,如果您想要与 2.x 相同的行为,您现在必须在执行之前明确地将其拉入内存 - 然而,这通常可能表明最好改变您的方式查询已完成 - 除非您确实明确需要此行为
有关更改的更多详细信息,请参阅 Here
此查询在 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);
我想将我的 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 核心 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.
这背后的原因是 EF Core 3 处理此类情况的方式发生了变化。
在 EF 核心 2.x 中,它被拉入内存并在那里自动完成操作,由于这样做的潜在性能问题,EF 核心团队决定将其从默认设置中移除错误行为是默认行为。
本质上,如果您想要与 2.x 相同的行为,您现在必须在执行之前明确地将其拉入内存 - 然而,这通常可能表明最好改变您的方式查询已完成 - 除非您确实明确需要此行为
有关更改的更多详细信息,请参阅 Here
此查询在 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);