Skip to content

Commit 8afb193

Browse files
authored
Merge pull request #130 from PhenX/feature/query-filters
Handle global query filters (Fixes #81)
2 parents 0e5c280 + b204527 commit 8afb193

File tree

6 files changed

+91
-0
lines changed

6 files changed

+91
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
2+
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
3+
4+
namespace EntityFrameworkCore.Projectables.Infrastructure.Internal;
5+
6+
public class CustomConventionSetPlugin : IConventionSetPlugin
7+
{
8+
public ConventionSet ModifyConventions(ConventionSet conventionSet)
9+
{
10+
conventionSet.ModelFinalizingConventions.Add(new ProjectablesExpandQueryFiltersConvention());
11+
12+
return conventionSet;
13+
}
14+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Linq.Expressions;
2+
using EntityFrameworkCore.Projectables.Extensions;
3+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
4+
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
5+
6+
namespace EntityFrameworkCore.Projectables.Infrastructure.Internal;
7+
8+
public class ProjectablesExpandQueryFiltersConvention : IModelFinalizingConvention
9+
{
10+
11+
/// <inheritdoc />
12+
public void ProcessModelFinalizing(
13+
IConventionModelBuilder modelBuilder,
14+
IConventionContext<IConventionModelBuilder> context)
15+
{
16+
foreach (var entityType in modelBuilder.Metadata.GetEntityTypes())
17+
{
18+
var queryFilter = entityType.GetQueryFilter();
19+
if (queryFilter != null)
20+
{
21+
// Expands query filters
22+
entityType.SetQueryFilter(queryFilter.ExpandProjectables() as LambdaExpression);
23+
}
24+
}
25+
}
26+
}

src/EntityFrameworkCore.Projectables/Infrastructure/Internal/ProjectionOptionsExtension.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ static object CreateTargetInstance(IServiceProvider services, ServiceDescriptor
5454
return ActivatorUtilities.GetServiceOrCreateInstance(services, descriptor.ImplementationType!);
5555
}
5656

57+
// Custom convention to handle global query filters, etc
58+
services.AddScoped<IConventionSetPlugin, CustomConventionSetPlugin>();
59+
5760
if (_compatibilityMode is CompatibilityMode.Full)
5861
{
5962
var targetDescriptor = services.FirstOrDefault(x => x.ServiceType == typeof(IQueryCompiler));
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
SELECT [t0].[RecordDate]
2+
FROM [User] AS [u]
3+
INNER JOIN (
4+
SELECT [t].[RecordDate], [t].[UserId]
5+
FROM (
6+
SELECT [o0].[RecordDate], [o0].[UserId], ROW_NUMBER() OVER(PARTITION BY [o0].[UserId] ORDER BY [o0].[RecordDate] DESC) AS [row]
7+
FROM [Order] AS [o0]
8+
) AS [t]
9+
WHERE [t].[row] <= 2
10+
) AS [t0] ON [u].[Id] = [t0].[UserId]
11+
WHERE (
12+
SELECT TOP(1) [o].[Id]
13+
FROM [Order] AS [o]
14+
WHERE [u].[Id] = [o].[UserId]
15+
ORDER BY [o].[RecordDate] DESC) > 100

tests/EntityFrameworkCore.Projectables.FunctionalTests/ComplexModelTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,17 @@ public Task ProjectOverMethodTakingDbContext()
8686

8787
return Verifier.Verify(query.ToQueryString());
8888
}
89+
90+
[Fact]
91+
public Task ProjectQueryFilters()
92+
{
93+
using var dbContext = new SampleUserWithGlobalQueryFilterDbContext();
94+
95+
var query = dbContext.Set<User>()
96+
.SelectMany(x => x.Last2Orders)
97+
.Select(x => x.RecordDate);
98+
99+
return Verifier.Verify(query.ToQueryString());
100+
}
89101
}
90102
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using EntityFrameworkCore.Projectables.Infrastructure;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace EntityFrameworkCore.Projectables.FunctionalTests.Helpers
5+
{
6+
public class SampleUserWithGlobalQueryFilterDbContext : SampleDbContext<ComplexModelTests.User>
7+
{
8+
public SampleUserWithGlobalQueryFilterDbContext(CompatibilityMode compatibilityMode = CompatibilityMode.Full) : base(compatibilityMode)
9+
{
10+
}
11+
12+
protected override void OnModelCreating(ModelBuilder modelBuilder)
13+
{
14+
base.OnModelCreating(modelBuilder);
15+
16+
modelBuilder.Entity<ComplexModelTests.User>(b => {
17+
b.HasQueryFilter(u => u.LastOrder.Id > 100);
18+
});
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)