Fixed concurrency bug

This commit is contained in:
Koen
2022-10-13 12:38:56 +01:00
parent 5e075c93bc
commit ed7f8c5940
7 changed files with 25 additions and 61 deletions
+3 -2
View File
@@ -92,11 +92,12 @@ namespace BasicSample
dbConnection.Open(); dbConnection.Open();
using var serviceProvider = new ServiceCollection() using var serviceProvider = new ServiceCollection()
.AddDbContext<ApplicationDbContext>(options => { .AddEntityFrameworkSqlServer()
.AddDbContext<ApplicationDbContext>((provider, options) => {
options options
.UseSqlite(dbConnection) .UseSqlite(dbConnection)
.UseProjectables() .UseProjectables()
.UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole())); .UseInternalServiceProvider(provider);
}) })
.BuildServiceProvider(); .BuildServiceProvider();
@@ -10,8 +10,6 @@ namespace EntityFrameworkCore.Projectables.Extensions
{ {
public static class ExpressionExtensions public static class ExpressionExtensions
{ {
static ProjectableExpressionReplacer _projectableExpressionReplacer = new ProjectableExpressionReplacer(new ProjectionExpressionResolver());
[Obsolete("Use ExpandProjectables instead")] [Obsolete("Use ExpandProjectables instead")]
public static Expression ExpandQuaryables(this Expression expression) public static Expression ExpandQuaryables(this Expression expression)
=> ExpandProjectables(expression); => ExpandProjectables(expression);
@@ -20,6 +18,6 @@ namespace EntityFrameworkCore.Projectables.Extensions
/// Replaces all calls to properties and methods that are marked with the <C>Projectable</C> attribute with their respective expression tree /// Replaces all calls to properties and methods that are marked with the <C>Projectable</C> attribute with their respective expression tree
/// </summary> /// </summary>
public static Expression ExpandProjectables(this Expression expression) public static Expression ExpandProjectables(this Expression expression)
=> _projectableExpressionReplacer.Visit(expression); => new ProjectableExpressionReplacer(new ProjectionExpressionResolver()).Visit(expression);
} }
} }
@@ -1,39 +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 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);
}
}
@@ -0,0 +1,19 @@
using System.Linq.Expressions;
using EntityFrameworkCore.Projectables.Extensions;
using Microsoft.EntityFrameworkCore.Query;
namespace EntityFrameworkCore.Projectables.Infrastructure.Internal
{
public class CustomQueryTranslationPreprocessor : QueryTranslationPreprocessor
{
readonly QueryTranslationPreprocessor _decoratedPreprocessor;
public CustomQueryTranslationPreprocessor(QueryTranslationPreprocessor decoratedPreprocessor, QueryTranslationPreprocessorDependencies dependencies, QueryCompilationContext queryCompilationContext) : base(dependencies, queryCompilationContext)
{
_decoratedPreprocessor = decoratedPreprocessor;
}
public override Expression Process(Expression query)
=> _decoratedPreprocessor.Process(query.ExpandProjectables());
}
}
@@ -1,10 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using EntityFrameworkCore.Projectables.Extensions;
using EntityFrameworkCore.Projectables.Services; using EntityFrameworkCore.Projectables.Services;
using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Query;
@@ -24,17 +22,4 @@ namespace EntityFrameworkCore.Projectables.Infrastructure.Internal
public QueryTranslationPreprocessor Create(QueryCompilationContext queryCompilationContext) public QueryTranslationPreprocessor Create(QueryCompilationContext queryCompilationContext)
=> new CustomQueryTranslationPreprocessor(_decoratedFactory.Create(queryCompilationContext), _queryTranslationPreprocessorDependencies, queryCompilationContext); => new CustomQueryTranslationPreprocessor(_decoratedFactory.Create(queryCompilationContext), _queryTranslationPreprocessorDependencies, queryCompilationContext);
} }
public class CustomQueryTranslationPreprocessor : QueryTranslationPreprocessor
{
readonly QueryTranslationPreprocessor _decoratedPreprocessor;
public CustomQueryTranslationPreprocessor(QueryTranslationPreprocessor decoratedPreprocessor, QueryTranslationPreprocessorDependencies dependencies, QueryCompilationContext queryCompilationContext) : base(dependencies, queryCompilationContext)
{
_decoratedPreprocessor = decoratedPreprocessor;
}
public override Expression Process(Expression query)
=> _decoratedPreprocessor.Process(query.ExpandProjectables());
}
} }
@@ -57,7 +57,7 @@ namespace EntityFrameworkCore.Projectables.Infrastructure.Internal
throw new InvalidOperationException("No QueryProvider 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(CustomQueryProvider), new[] { targetDescriptor.ServiceType }); var decoratorObjectFactory = ActivatorUtilities.CreateFactory(typeof(CustomQueryCompiler), new[] { targetDescriptor.ServiceType });
services.Replace(ServiceDescriptor.Describe( services.Replace(ServiceDescriptor.Describe(
targetDescriptor.ServiceType, targetDescriptor.ServiceType,
@@ -22,7 +22,7 @@ namespace EntityFrameworkCore.Projectables.FunctionalTests.Helpers
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
optionsBuilder.UseSqlServer("Server=(localdb)\v11.0;Integrated Security=true"); // Fake connection string as we're actually never connecting optionsBuilder.UseSqlServer("Server=(localdb)\\v11.0;Integrated Security=true"); // Fake connection string as we're actually never connecting
optionsBuilder.UseProjectables(options => { optionsBuilder.UseProjectables(options => {
options.CompatibilityMode(_compatibilityMode); // Needed by our ComplexModelTests options.CompatibilityMode(_compatibilityMode); // Needed by our ComplexModelTests
}); });