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

View File

@@ -92,11 +92,12 @@ namespace BasicSample
dbConnection.Open();
using var serviceProvider = new ServiceCollection()
.AddDbContext<ApplicationDbContext>(options => {
.AddEntityFrameworkSqlServer()
.AddDbContext<ApplicationDbContext>((provider, options) => {
options
.UseSqlite(dbConnection)
.UseProjectables()
.UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()));
.UseInternalServiceProvider(provider);
})
.BuildServiceProvider();

View File

@@ -10,8 +10,6 @@ namespace EntityFrameworkCore.Projectables.Extensions
{
public static class ExpressionExtensions
{
static ProjectableExpressionReplacer _projectableExpressionReplacer = new ProjectableExpressionReplacer(new ProjectionExpressionResolver());
[Obsolete("Use ExpandProjectables instead")]
public static Expression ExpandQuaryables(this Expression 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
/// </summary>
public static Expression ExpandProjectables(this Expression expression)
=> _projectableExpressionReplacer.Visit(expression);
=> new ProjectableExpressionReplacer(new ProjectionExpressionResolver()).Visit(expression);
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -1,10 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using EntityFrameworkCore.Projectables.Extensions;
using EntityFrameworkCore.Projectables.Services;
using Microsoft.EntityFrameworkCore.Query;
@@ -24,17 +22,4 @@ namespace EntityFrameworkCore.Projectables.Infrastructure.Internal
public QueryTranslationPreprocessor Create(QueryCompilationContext 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());
}
}

View File

@@ -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"); ;
}
var decoratorObjectFactory = ActivatorUtilities.CreateFactory(typeof(CustomQueryProvider), new[] { targetDescriptor.ServiceType });
var decoratorObjectFactory = ActivatorUtilities.CreateFactory(typeof(CustomQueryCompiler), new[] { targetDescriptor.ServiceType });
services.Replace(ServiceDescriptor.Describe(
targetDescriptor.ServiceType,

View File

@@ -22,7 +22,7 @@ namespace EntityFrameworkCore.Projectables.FunctionalTests.Helpers
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 => {
options.CompatibilityMode(_compatibilityMode); // Needed by our ComplexModelTests
});