更新(EF Core 3.x):
内部查询管道基础设施已发生变化。新的查询表达式预处理扩展点是查询翻译预处理器 https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.query.querytranslationpreprocessor?view=efcore-3.1班级 -Process https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.query.querytranslationpreprocessor.process?view=efcore-3.1方法。将其插入需要更换IQueryTranslationPreprocessorFactory https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.query.iquerytranslationpreprocessorfactory?view=efcore-3.1. e.g.
using System.Linq.Expressions;
namespace Microsoft.EntityFrameworkCore.Query
{
public class CustomQueryTranslationPreprocessor : RelationalQueryTranslationPreprocessor
{
public CustomQueryTranslationPreprocessor(QueryTranslationPreprocessorDependencies dependencies, RelationalQueryTranslationPreprocessorDependencies relationalDependencies, QueryCompilationContext queryCompilationContext)
: base(dependencies, relationalDependencies, queryCompilationContext) { }
public override Expression Process(Expression query) => base.Process(Preprocess(query));
private Expression Preprocess(Expression query)
{
// query = new YourExpressionVisitor().Visit(query);
return query;
}
}
public class CustomQueryTranslationPreprocessorFactory : IQueryTranslationPreprocessorFactory
{
public CustomQueryTranslationPreprocessorFactory(QueryTranslationPreprocessorDependencies dependencies, RelationalQueryTranslationPreprocessorDependencies relationalDependencies)
{
Dependencies = dependencies;
RelationalDependencies = relationalDependencies;
}
protected QueryTranslationPreprocessorDependencies Dependencies { get; }
protected RelationalQueryTranslationPreprocessorDependencies RelationalDependencies;
public QueryTranslationPreprocessor Create(QueryCompilationContext queryCompilationContext)
=> new CustomQueryTranslationPreprocessor(Dependencies, RelationalDependencies, queryCompilationContext);
}
}
and
optionsBuilder.ReplaceService<IQueryTranslationPreprocessorFactory, CustomQueryTranslationPreprocessorFactory>();
原来的:
显然,自定义查询提供程序不适合当前的 EF Core 可查询管道,因为有几种方法(Include
, AsNoTracking
等)要求提供者是EntityQueryProvider
.
在撰写本文时(EF Core 2.1.2),查询转换过程涉及多项服务 -IAsyncQueryProvider
, IQueryCompiler
, IQueryModelGenerator
和更多。它们都是可替换的,但我看到最容易拦截的地方是IQueryModelGenerator
服务 -ParseQuery
method.
所以,忘记习惯吧IQueryable
/ IQueryProvider
实现,使用以下类并将表达式访问者插入其中Preprocess
method:
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Remotion.Linq;
using Remotion.Linq.Parsing.ExpressionVisitors.TreeEvaluation;
class CustomQueryModelGenerator : QueryModelGenerator
{
public CustomQueryModelGenerator(INodeTypeProviderFactory nodeTypeProviderFactory, IEvaluatableExpressionFilter evaluatableExpressionFilter, ICurrentDbContext currentDbContext)
: base(nodeTypeProviderFactory, evaluatableExpressionFilter, currentDbContext)
{ }
public override QueryModel ParseQuery(Expression query) => base.ParseQuery(Preprocess(query));
private Expression Preprocess(Expression query)
{
// return new YourExpressionVisitor().Visit(query);
return query;
}
}
并替换派生上下文中相应的 EF Core 服务OnConfiguring
覆盖:
optionsBuilder.ReplaceService<IQueryModelGenerator, CustomQueryModelGenerator>();
缺点是这是使用 EF Core“内部”内容,因此您应该继续监视未来更新中的更改。