mirror of
https://github.com/zoriya/EntityFrameworkCore.Projectables.git
synced 2026-05-31 21:48:12 +00:00
Use more effective EF hook to register our custom provider
This commit is contained in:
+40
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using EntityFrameworkCore.Projections.Services;
|
||||||
|
using Microsoft.EntityFrameworkCore.Query;
|
||||||
|
|
||||||
|
namespace EntityFrameworkCore.Projections.Infrastructure.Internal
|
||||||
|
{
|
||||||
|
public class CustomQueryTranslationPreprocessorFactory : IQueryTranslationPreprocessorFactory
|
||||||
|
{
|
||||||
|
readonly IQueryTranslationPreprocessorFactory _decoratedFactory;
|
||||||
|
readonly QueryTranslationPreprocessorDependencies _queryTranslationPreprocessorDependencies;
|
||||||
|
readonly ProjectableExpressionReplacer _projectableExpressionReplacer = new();
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
-10
@@ -2,8 +2,10 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Query;
|
using Microsoft.EntityFrameworkCore.Query;
|
||||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
using Microsoft.EntityFrameworkCore.Query.Internal;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -22,23 +24,35 @@ namespace EntityFrameworkCore.Projections.Infrastructure.Internal
|
|||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Needed")]
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Needed")]
|
||||||
public void ApplyServices(IServiceCollection services)
|
public void ApplyServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
var queryCompilerRegistration = services.FirstOrDefault(x => x.ServiceType == typeof(IQueryCompiler));
|
static object CreateTargetInstance(IServiceProvider services, ServiceDescriptor descriptor)
|
||||||
if (queryCompilerRegistration?.ImplementationType is null)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("No queryCompiler is configured yet. Please make sure to configure a database provider first"); ;
|
if (descriptor.ImplementationInstance is not null)
|
||||||
|
return descriptor.ImplementationInstance;
|
||||||
|
|
||||||
|
if (descriptor.ImplementationFactory is not null)
|
||||||
|
return descriptor.ImplementationFactory(services);
|
||||||
|
|
||||||
|
Debug.Assert(descriptor.ImplementationType is not null);
|
||||||
|
|
||||||
|
return ActivatorUtilities.GetServiceOrCreateInstance(services, descriptor.ImplementationType!);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that we can still resolve this queryCompiler
|
var targetDescriptor = services.FirstOrDefault(x => x.ServiceType == typeof(IQueryTranslationPreprocessorFactory));
|
||||||
services.Add(new ServiceDescriptor(queryCompilerRegistration.ImplementationType, queryCompilerRegistration.ImplementationType, queryCompilerRegistration.Lifetime));
|
if (targetDescriptor is null)
|
||||||
services.Remove(queryCompilerRegistration);
|
{
|
||||||
|
throw new InvalidOperationException("No QueryTranslationPreprocessorFactory is configured yet. Please make sure to configure a database provider first"); ;
|
||||||
|
}
|
||||||
|
|
||||||
services.Add(new ServiceDescriptor(
|
var decoratorObjectFactory = ActivatorUtilities.CreateFactory(typeof(CustomQueryTranslationPreprocessorFactory), new [] { targetDescriptor.ServiceType });
|
||||||
typeof(IQueryCompiler),
|
|
||||||
serviceProvider => new WrappedQueryCompiler((IQueryCompiler)serviceProvider.GetRequiredService(queryCompilerRegistration.ImplementationType)),
|
services.Replace(ServiceDescriptor.Describe(
|
||||||
queryCompilerRegistration.Lifetime
|
targetDescriptor.ServiceType,
|
||||||
|
serviceProvider => decoratorObjectFactory(serviceProvider, new[] { CreateTargetInstance(serviceProvider, targetDescriptor) }),
|
||||||
|
targetDescriptor.Lifetime
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Validate(IDbContextOptions options)
|
public void Validate(IDbContextOptions options)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using EntityFrameworkCore.Projections.Services;
|
|
||||||
using Microsoft.EntityFrameworkCore.Query;
|
|
||||||
using Microsoft.EntityFrameworkCore.Query.Internal;
|
|
||||||
|
|
||||||
namespace EntityFrameworkCore.Projections.Infrastructure.Internal
|
|
||||||
{
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Needed")]
|
|
||||||
public sealed class WrappedQueryCompiler : IQueryCompiler
|
|
||||||
{
|
|
||||||
readonly ProjectableExpressionReplacer _projectionExpressionReplacer = new();
|
|
||||||
readonly IQueryCompiler _queryCompiler;
|
|
||||||
|
|
||||||
public WrappedQueryCompiler(IQueryCompiler queryCompiler)
|
|
||||||
{
|
|
||||||
_queryCompiler = queryCompiler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Func<QueryContext, TResult> CreateCompiledAsyncQuery<TResult>(Expression query)
|
|
||||||
=> _queryCompiler.CreateCompiledAsyncQuery<TResult>(PatchQuery(query));
|
|
||||||
|
|
||||||
public Func<QueryContext, TResult> CreateCompiledQuery<TResult>(Expression query)
|
|
||||||
=> _queryCompiler.CreateCompiledQuery<TResult>(PatchQuery(query));
|
|
||||||
|
|
||||||
public TResult Execute<TResult>(Expression query)
|
|
||||||
=> _queryCompiler.Execute<TResult>(PatchQuery(query));
|
|
||||||
|
|
||||||
public TResult ExecuteAsync<TResult>(Expression query, CancellationToken cancellationToken)
|
|
||||||
=> _queryCompiler.ExecuteAsync<TResult>(PatchQuery(query), cancellationToken);
|
|
||||||
|
|
||||||
Expression PatchQuery(Expression expression)
|
|
||||||
=> _projectionExpressionReplacer.Visit(expression);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user