Ability to have projectable methods that accept a DbContext

This commit is contained in:
Koen Bekkenutte
2021-06-02 23:44:40 +08:00
parent 6f2b30f723
commit 3aa2c811df
8 changed files with 100 additions and 46 deletions
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Transactions;
using EntityFrameworkCore.Projectables.Services;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.Internal;
namespace EntityFrameworkCore.Projectables.Infrastructure.Internal
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Needed")]
public sealed class CustomQueryProvider : IQueryCompiler
{
readonly IQueryCompiler _decoratedQueryCompiler;
readonly ProjectableExpressionReplacer _projectableExpressionReplacer;
public CustomQueryProvider(IQueryCompiler decoratedQueryCompiler)
{
_decoratedQueryCompiler = decoratedQueryCompiler;
_projectableExpressionReplacer = new ProjectableExpressionReplacer(new ProjectionExpressionResolver());
}
public Func<QueryContext, TResult> CreateCompiledAsyncQuery<TResult>(Expression query)
=> _decoratedQueryCompiler.CreateCompiledAsyncQuery<TResult>(Expand(query));
public Func<QueryContext, TResult> CreateCompiledQuery<TResult>(Expression query)
=> _decoratedQueryCompiler.CreateCompiledQuery<TResult>(Expand(query));
public TResult Execute<TResult>(Expression query)
=> _decoratedQueryCompiler.Execute<TResult>(Expand(query));
public TResult ExecuteAsync<TResult>(Expression query, CancellationToken cancellationToken)
=> _decoratedQueryCompiler.ExecuteAsync<TResult>(Expand(query), cancellationToken);
Expression Expand(Expression expression)
=> _projectableExpressionReplacer.Visit(expression);
}
}
@@ -1,40 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using EntityFrameworkCore.Projectables.Services;
using Microsoft.EntityFrameworkCore.Query;
namespace EntityFrameworkCore.Projectables.Infrastructure.Internal
{
public class CustomQueryTranslationPreprocessorFactory : IQueryTranslationPreprocessorFactory
{
readonly IQueryTranslationPreprocessorFactory _decoratedFactory;
readonly QueryTranslationPreprocessorDependencies _queryTranslationPreprocessorDependencies;
readonly ProjectableExpressionReplacer _projectableExpressionReplacer = new(new ProjectionExpressionResolver());
public CustomQueryTranslationPreprocessorFactory(IQueryTranslationPreprocessorFactory decoratedFactory, QueryTranslationPreprocessorDependencies queryTranslationPreprocessorDependencies)
{
_decoratedFactory = decoratedFactory;
_queryTranslationPreprocessorDependencies = queryTranslationPreprocessorDependencies;
}
public QueryTranslationPreprocessor Create(QueryCompilationContext queryCompilationContext)
=> new CustomQueryTranslationPreprocessor(_queryTranslationPreprocessorDependencies, queryCompilationContext, _projectableExpressionReplacer);
}
public class CustomQueryTranslationPreprocessor : QueryTranslationPreprocessor
{
readonly ProjectableExpressionReplacer _projectableExpressionReplacer;
public CustomQueryTranslationPreprocessor(QueryTranslationPreprocessorDependencies dependencies, QueryCompilationContext queryCompilationContext, ProjectableExpressionReplacer projectableExpressionReplacer) : base(dependencies, queryCompilationContext)
{
_projectableExpressionReplacer = projectableExpressionReplacer;
}
public override Expression Process(Expression query)
=> base.Process(_projectableExpressionReplacer.Visit(query));
}
}
@@ -37,13 +37,13 @@ namespace EntityFrameworkCore.Projectables.Infrastructure.Internal
return ActivatorUtilities.GetServiceOrCreateInstance(services, descriptor.ImplementationType!);
}
var targetDescriptor = services.FirstOrDefault(x => x.ServiceType == typeof(IQueryTranslationPreprocessorFactory));
var targetDescriptor = services.FirstOrDefault(x => x.ServiceType == typeof(IQueryCompiler));
if (targetDescriptor is null)
{
throw new InvalidOperationException("No QueryTranslationPreprocessorFactory is configured yet. Please make sure to configure a database provider first"); ;
throw new InvalidOperationException("No QueryProvider is configured yet. Please make sure to configure a database provider first"); ;
}
var decoratorObjectFactory = ActivatorUtilities.CreateFactory(typeof(CustomQueryTranslationPreprocessorFactory), new [] { targetDescriptor.ServiceType });
var decoratorObjectFactory = ActivatorUtilities.CreateFactory(typeof(CustomQueryProvider), new [] { targetDescriptor.ServiceType });
services.Replace(ServiceDescriptor.Describe(
targetDescriptor.ServiceType,
@@ -52,7 +52,6 @@ namespace EntityFrameworkCore.Projectables.Infrastructure.Internal
));
}
public void Validate(IDbContextOptions options)
{
}