diff --git a/Directory.Build.props b/Directory.Build.props index d79998e..cd0f7dd 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -30,4 +30,4 @@ - \ No newline at end of file + diff --git a/samples/BasicSample/Program.cs b/samples/BasicSample/Program.cs index 4cd2957..c2be8b4 100644 --- a/samples/BasicSample/Program.cs +++ b/samples/BasicSample/Program.cs @@ -22,7 +22,6 @@ namespace BasicSample private string _FullName => FirstName + " " + LastName; [Projectable(UseMemberBody = nameof(_TotalSpent))] - [NotMapped] public double TotalSpent { get; set; } private double _TotalSpent => Orders.Sum(x => x.PriceSum); @@ -92,7 +91,7 @@ namespace BasicSample .AddDbContext((provider, options) => { options .UseSqlite(dbConnection) - .LogTo(Console.WriteLine) + // .LogTo(Console.WriteLine) .EnableSensitiveDataLogging() .UseProjectables(); }) diff --git a/src/EntityFrameworkCore.Projectables/Extensions/ExpressionExtensions.cs b/src/EntityFrameworkCore.Projectables/Extensions/ExpressionExtensions.cs index 565e784..49da220 100644 --- a/src/EntityFrameworkCore.Projectables/Extensions/ExpressionExtensions.cs +++ b/src/EntityFrameworkCore.Projectables/Extensions/ExpressionExtensions.cs @@ -18,6 +18,6 @@ namespace EntityFrameworkCore.Projectables.Extensions /// Replaces all calls to properties and methods that are marked with the Projectable attribute with their respective expression tree /// public static Expression ExpandProjectables(this Expression expression) - => new ProjectableExpressionReplacer(new ProjectionExpressionResolver()).Visit(expression); + => new ProjectableExpressionReplacer(new ProjectionExpressionResolver()).Replace(expression); } } diff --git a/src/EntityFrameworkCore.Projectables/Infrastructure/Internal/CustomQueryCompiler.cs b/src/EntityFrameworkCore.Projectables/Infrastructure/Internal/CustomQueryCompiler.cs index 5a300a2..2a85c9c 100644 --- a/src/EntityFrameworkCore.Projectables/Infrastructure/Internal/CustomQueryCompiler.cs +++ b/src/EntityFrameworkCore.Projectables/Infrastructure/Internal/CustomQueryCompiler.cs @@ -34,6 +34,6 @@ namespace EntityFrameworkCore.Projectables.Infrastructure.Internal => _decoratedQueryCompiler.ExecuteAsync(Expand(query), cancellationToken); Expression Expand(Expression expression) - => _projectableExpressionReplacer.Visit(expression); + => _projectableExpressionReplacer.Replace(expression); } } diff --git a/src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs b/src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs index db66e3d..f9e8212 100644 --- a/src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs +++ b/src/EntityFrameworkCore.Projectables/Services/ProjectableExpressionReplacer.cs @@ -13,15 +13,13 @@ namespace EntityFrameworkCore.Projectables.Services { readonly IProjectionExpressionResolver _resolver; readonly ExpressionArgumentReplacer _expressionArgumentReplacer = new(); - readonly QueryRootReplacer _queryRootReplacer; readonly Dictionary _projectableMemberCache = new(); - private bool _disableRootRewrite = false; + private bool _disableRootRewrite; private IEntityType? _entityType; public ProjectableExpressionReplacer(IProjectionExpressionResolver projectionExpressionResolver) { _resolver = projectionExpressionResolver; - _queryRootReplacer = new(_resolver); } bool TryGetReflectedExpression(MemberInfo memberInfo, [NotNullWhen(true)] out LambdaExpression? reflectedExpression) @@ -41,19 +39,19 @@ namespace EntityFrameworkCore.Projectables.Services } [return: NotNullIfNotNull(nameof(node))] - public override Expression? Visit(Expression? node) + public Expression? Replace(Expression? node) { - var ret = base.Visit(node); + var ret = Visit(node); if (_disableRootRewrite) { return ret; } - switch (node) + switch (ret) { // Probably a First() or ToList() - case MethodCallExpression { Arguments.Count: > 0 } call when _entityType != null: + case MethodCallExpression { Arguments.Count: > 0, Object: null } call when _entityType != null: { var self = _AddProjectableSelect(call.Arguments.First(), _entityType); return call.Update(null, call.Arguments.Skip(1).Prepend(self)); @@ -96,7 +94,7 @@ namespace EntityFrameworkCore.Projectables.Services var updatedBody = _expressionArgumentReplacer.Visit(reflectedExpression.Body); _expressionArgumentReplacer.ParameterArgumentMapping.Clear(); - return Visit( + return base.Visit( updatedBody ); } @@ -128,13 +126,13 @@ namespace EntityFrameworkCore.Projectables.Services var updatedBody = _expressionArgumentReplacer.Visit(reflectedExpression.Body); _expressionArgumentReplacer.ParameterArgumentMapping.Clear(); - return Visit( + return base.Visit( updatedBody ); } else { - return Visit( + return base.Visit( reflectedExpression.Body ); } @@ -190,7 +188,7 @@ namespace EntityFrameworkCore.Projectables.Services Expression.New(entityType.ClrType), properties.Select(x => Expression.Bind(x, Expression.MakeMemberAccess(xParam, x))) .Concat(projectableProperties - .Select(x => Expression.Bind(x, _ReplaceParam(_resolver.FindGeneratedExpression(x), xParam))) + .Select(x => Expression.Bind(x, _GetAccessor(x, xParam))) ) ), xParam @@ -198,12 +196,13 @@ namespace EntityFrameworkCore.Projectables.Services ); } - private Expression _ReplaceParam(LambdaExpression lambda, ParameterExpression para) + private Expression _GetAccessor(PropertyInfo property, ParameterExpression para) { + var lambda = _resolver.FindGeneratedExpression(property); _expressionArgumentReplacer.ParameterArgumentMapping.Add(lambda.Parameters[0], para); var updatedBody = _expressionArgumentReplacer.Visit(lambda.Body); _expressionArgumentReplacer.ParameterArgumentMapping.Clear(); - return updatedBody; + return base.Visit(updatedBody); } } } diff --git a/tests/EntityFrameworkCore.Projectables.FunctionalTests/QueryRootTests.UseMemberPropertyQueryRootExpression.verified.txt b/tests/EntityFrameworkCore.Projectables.FunctionalTests/QueryRootTests.UseMemberPropertyQueryRootExpression.verified.txt index 7d6c73b..e8c699d 100644 --- a/tests/EntityFrameworkCore.Projectables.FunctionalTests/QueryRootTests.UseMemberPropertyQueryRootExpression.verified.txt +++ b/tests/EntityFrameworkCore.Projectables.FunctionalTests/QueryRootTests.UseMemberPropertyQueryRootExpression.verified.txt @@ -1,2 +1,2 @@ SELECT [e].[Id], [e].[Id] * 5 -FROM [Entity] AS [e] +FROM [Entity] AS [e] \ No newline at end of file diff --git a/tests/EntityFrameworkCore.Projectables.Tests/Services/ProjectableExpressionReplacerTests.cs b/tests/EntityFrameworkCore.Projectables.Tests/Services/ProjectableExpressionReplacerTests.cs index 133baeb..a9ed5dd 100644 --- a/tests/EntityFrameworkCore.Projectables.Tests/Services/ProjectableExpressionReplacerTests.cs +++ b/tests/EntityFrameworkCore.Projectables.Tests/Services/ProjectableExpressionReplacerTests.cs @@ -61,7 +61,7 @@ namespace EntityFrameworkCore.Projectables.Tests.Services ); var subject = new ProjectableExpressionReplacer(resolver); - var actual = subject.Visit(input); + var actual = subject.Replace(input); Assert.Equal(expected.ToString(), actual.ToString()); } @@ -77,7 +77,7 @@ namespace EntityFrameworkCore.Projectables.Tests.Services ); var subject = new ProjectableExpressionReplacer(resolver); - var actual = subject.Visit(input); + var actual = subject.Replace(input); Assert.Equal(expected.ToString(), actual.ToString()); } @@ -93,7 +93,7 @@ namespace EntityFrameworkCore.Projectables.Tests.Services ); var subject = new ProjectableExpressionReplacer(resolver); - var actual = subject.Visit(input); + var actual = subject.Replace(input); Assert.Equal(expected.ToString(), actual.ToString()); } @@ -109,7 +109,7 @@ namespace EntityFrameworkCore.Projectables.Tests.Services ); var subject = new ProjectableExpressionReplacer(resolver); - var actual = subject.Visit(input); + var actual = subject.Replace(input); Assert.Equal(expected.ToString(), actual.ToString()); } @@ -125,7 +125,7 @@ namespace EntityFrameworkCore.Projectables.Tests.Services ); var subject = new ProjectableExpressionReplacer(resolver); - var actual = subject.Visit(input); + var actual = subject.Replace(input); Assert.Equal(expected.ToString(), actual.ToString()); } @@ -141,7 +141,7 @@ namespace EntityFrameworkCore.Projectables.Tests.Services ); var subject = new ProjectableExpressionReplacer(resolver); - var actual = subject.Visit(input); + var actual = subject.Replace(input); Assert.Equal(expected.ToString(), actual.ToString()); } @@ -157,7 +157,7 @@ namespace EntityFrameworkCore.Projectables.Tests.Services ); var subject = new ProjectableExpressionReplacer(resolver); - var actual = subject.Visit(input); + var actual = subject.Replace(input); Assert.Equal(expected.ToString(), actual.ToString()); }