diff --git a/AutoMapper.AspNetCore.OData.EFCore/ProjectionSettings.cs b/AutoMapper.AspNetCore.OData.EFCore/ProjectionSettings.cs index e5c606a..80c6a27 100644 --- a/AutoMapper.AspNetCore.OData.EFCore/ProjectionSettings.cs +++ b/AutoMapper.AspNetCore.OData.EFCore/ProjectionSettings.cs @@ -10,5 +10,6 @@ namespace AutoMapper.AspNet.OData public class ProjectionSettings { public object Parameters { get; set; } + public bool ApplyFilterAfterProjection { get; set; } } } diff --git a/AutoMapper.AspNetCore.OData.EFCore/QueryableExtensions.cs b/AutoMapper.AspNetCore.OData.EFCore/QueryableExtensions.cs index fcd6f4a..665fc35 100644 --- a/AutoMapper.AspNetCore.OData.EFCore/QueryableExtensions.cs +++ b/AutoMapper.AspNetCore.OData.EFCore/QueryableExtensions.cs @@ -154,19 +154,24 @@ private static IQueryable GetQuery(this IQueryable IEnumerable>> includeProperties = null, ProjectionSettings projectionSettings = null) { - Expression> f = mapper.MapExpression>>(filter); Func, IQueryable> mappedQueryFunc = mapper.MapExpression, IQueryable>>>(queryFunc)?.Compile(); - if (filter != null) - query = query.Where(f); + if (filter != null && !FilterAfterProjection()) + query = query.Where(mapper.MapExpression>>(filter)); - return mappedQueryFunc != null + var projectedQuery = mappedQueryFunc != null ? mapper.ProjectTo(mappedQueryFunc(query), projectionSettings?.Parameters, GetIncludes()) : mapper.ProjectTo(query, projectionSettings?.Parameters, GetIncludes()); + if (filter != null && FilterAfterProjection()) + projectedQuery = projectedQuery.Where(filter); + + return projectedQuery; + + bool FilterAfterProjection() => projectionSettings?.ApplyFilterAfterProjection ?? false; Expression>[] GetIncludes() => includeProperties?.ToArray() ?? new Expression>[] { }; } - + private static void ApplyOptions(this IQueryable query, IMapper mapper, Expression> filter, ODataQueryOptions options, QuerySettings querySettings) { ApplyOptions(options, querySettings); diff --git a/AutoMapper.OData.EFCore.Tests/GetQueryTests.cs b/AutoMapper.OData.EFCore.Tests/GetQueryTests.cs index 8d4203b..e241efd 100644 --- a/AutoMapper.OData.EFCore.Tests/GetQueryTests.cs +++ b/AutoMapper.OData.EFCore.Tests/GetQueryTests.cs @@ -416,7 +416,85 @@ void Test(ICollection collection) Assert.Equal("Two", collection.First().Name); } } + [Fact] + public async Task FilterByDynamicParameterValueAfterProjectionReturnExpectedResults() + { + // Arrange + string buildingParameterValue = Guid.NewGuid().ToString(); + + var parameters = new { buildingParameter = buildingParameterValue }; + + var projectionSettings = new ProjectionSettings + { + Parameters = parameters, + //if false test will fail + ApplyFilterAfterProjection = true + }; + + var odataSettings = new ODataSettings + { + HandleNullPropagation = HandleNullPropagationOption.False + }; + + string query = $"/corebuilding?$filter=Parameter eq '{buildingParameterValue}'"; + + // Act + var result = await GetAsync( + query, + null, + new QuerySettings + { + ProjectionSettings = projectionSettings, + ODataSettings = odataSettings + }); + + // Assert + if (result.Count == 0) + { + throw new Xunit.Sdk.XunitException( + "Expected at least one CoreBuilding with matching Parameter value, " + + "but none were returned. This replicates the case where a runtime parameter " + + "(like CurrentUserId) was not propagated during OData filter translation." + ); + } + Assert.All(result, b => Assert.Equal(buildingParameterValue, b.Parameter)); + } + + [Fact] + public async Task FilterByDynamicParameterValueBeforeProjectionReturnZeroResults() + { + // Arrange + string buildingParameterValue = Guid.NewGuid().ToString(); + + var parameters = new { buildingParameter = buildingParameterValue }; + + var projectionSettings = new ProjectionSettings + { + Parameters = parameters, + ApplyFilterAfterProjection = false + }; + + var odataSettings = new ODataSettings + { + HandleNullPropagation = HandleNullPropagationOption.False + }; + + string query = $"/corebuilding?$filter=Parameter eq '{buildingParameterValue}'"; + + // Act + var result = await GetAsync( + query, + null, + new QuerySettings + { + ProjectionSettings = projectionSettings, + ODataSettings = odataSettings + }); + + // Assert + Assert.Empty(result); + } [Fact] public async Task BuildingExpandBuilderTenantFilterEqAndOrderByWithParameter() {