Skip to content

Commit 1a9cd97

Browse files
authored
Add support for EnableConstantParameterization (#215)
* Add support of EnableConstantParameterization. * Add tests * reuse variable * move tests * remove whitespaces
1 parent dbb65ad commit 1a9cd97

File tree

5 files changed

+105
-22
lines changed

5 files changed

+105
-22
lines changed

AutoMapper.AspNetCore.OData.EF6/QueryableExtensions.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ public static class QueryableExtensions
2626
public static ICollection<TModel> Get<TModel, TData>(this IQueryable<TData> query, IMapper mapper, ODataQueryOptions<TModel> options, QuerySettings querySettings)
2727
where TModel : class
2828
{
29-
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>(querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.Default);
29+
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>
30+
(
31+
querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.Default,
32+
enableConstantParameterization: querySettings?.ODataSettings?.EnableConstantParameterization ?? true
33+
);
3034
query.ApplyOptions(mapper, filter, options, querySettings);
3135
return query.Get
3236
(
@@ -50,7 +54,11 @@ public static ICollection<TModel> Get<TModel, TData>(this IQueryable<TData> quer
5054
public static async Task<ICollection<TModel>> GetAsync<TModel, TData>(this IQueryable<TData> query, IMapper mapper, ODataQueryOptions<TModel> options, QuerySettings querySettings = null)
5155
where TModel : class
5256
{
53-
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>(querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.Default);
57+
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>
58+
(
59+
querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.Default,
60+
enableConstantParameterization: querySettings?.ODataSettings?.EnableConstantParameterization ?? true
61+
);
5462
await query.ApplyOptionsAsync(mapper, filter, options, querySettings);
5563
return await query.GetAsync
5664
(
@@ -75,7 +83,11 @@ public static async Task<ICollection<TModel>> GetAsync<TModel, TData>(this IQuer
7583
public static async Task<IQueryable<TModel>> GetQueryAsync<TModel, TData>(this IQueryable<TData> query, IMapper mapper, ODataQueryOptions<TModel> options, QuerySettings querySettings = null)
7684
where TModel : class
7785
{
78-
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>(querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.False);
86+
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>
87+
(
88+
querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.False,
89+
enableConstantParameterization: querySettings?.ODataSettings?.EnableConstantParameterization ?? true
90+
);
7991
await query.ApplyOptionsAsync(mapper, filter, options, querySettings);
8092
return query.GetQueryable(mapper, options, querySettings, filter);
8193
}
@@ -93,7 +105,11 @@ public static async Task<IQueryable<TModel>> GetQueryAsync<TModel, TData>(this I
93105
public static IQueryable<TModel> GetQuery<TModel, TData>(this IQueryable<TData> query, IMapper mapper, ODataQueryOptions<TModel> options, QuerySettings querySettings = null)
94106
where TModel : class
95107
{
96-
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>(querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.False);
108+
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>
109+
(
110+
querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.False,
111+
enableConstantParameterization: querySettings?.ODataSettings?.EnableConstantParameterization ?? true
112+
);
97113
query.ApplyOptions(mapper, filter, options, querySettings);
98114
return query.GetQueryable(mapper, options, querySettings, filter);
99115
}

AutoMapper.AspNetCore.OData.EFCore/LinqExtensions.cs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,20 @@ public static Expression ReplaceParameter(this Expression expression,
3333
/// <typeparam name="T"></typeparam>
3434
/// <param name="filterOption"></param>
3535
/// <returns></returns>
36-
public static Expression<Func<T, bool>> ToFilterExpression<T>(this FilterQueryOption filterOption, HandleNullPropagationOption handleNullPropagation = HandleNullPropagationOption.Default, TimeZoneInfo timeZone = null)
36+
public static Expression<Func<T, bool>> ToFilterExpression<T>(
37+
this FilterQueryOption filterOption,
38+
HandleNullPropagationOption handleNullPropagation = HandleNullPropagationOption.Default,
39+
TimeZoneInfo timeZone = null,
40+
bool enableConstantParameterization = true)
3741
{
3842
if (filterOption == null)
3943
return null;
4044

4145
IQueryable queryable = Enumerable.Empty<T>().AsQueryable();
4246

43-
queryable = filterOption.ApplyTo(queryable, new ODataQuerySettings() { HandleNullPropagation = handleNullPropagation, TimeZone = timeZone });
47+
queryable = filterOption.ApplyTo(
48+
queryable,
49+
new ODataQuerySettings() { HandleNullPropagation = handleNullPropagation, TimeZone = timeZone, EnableConstantParameterization = enableConstantParameterization });
4450

4551
MethodCallExpression whereMethodCallExpression = (MethodCallExpression)queryable.Expression;
4652

@@ -53,13 +59,19 @@ public static Expression<Func<T, bool>> ToFilterExpression<T>(this FilterQueryOp
5359
/// <typeparam name="T"></typeparam>
5460
/// <param name="filterOption"></param>
5561
/// <returns></returns>
56-
public static Expression<Func<T, bool>> ToSearchExpression<T>(this SearchQueryOption filterOption, HandleNullPropagationOption handleNullPropagation = HandleNullPropagationOption.Default, TimeZoneInfo timeZone = null)
62+
public static Expression<Func<T, bool>> ToSearchExpression<T>(
63+
this SearchQueryOption filterOption,
64+
HandleNullPropagationOption handleNullPropagation = HandleNullPropagationOption.Default,
65+
TimeZoneInfo timeZone = null,
66+
bool enableConstantParameterization = true)
5767
{
5868
if (filterOption == null)
5969
return null;
6070

6171
IQueryable queryable = Enumerable.Empty<T>().AsQueryable();
62-
queryable = filterOption.ApplyTo(queryable, new ODataQuerySettings() { HandleNullPropagation = handleNullPropagation, TimeZone = timeZone });
72+
queryable = filterOption.ApplyTo(
73+
queryable,
74+
new ODataQuerySettings() { HandleNullPropagation = handleNullPropagation, TimeZone = timeZone, EnableConstantParameterization = enableConstantParameterization });
6375

6476
MethodCallExpression whereMethodCallExpression = (MethodCallExpression)queryable.Expression;
6577

@@ -68,7 +80,8 @@ public static Expression<Func<T, bool>> ToSearchExpression<T>(this SearchQueryOp
6880

6981
public static Expression<Func<T, bool>> ToFilterExpression<T>(this ODataQueryOptions<T> options,
7082
HandleNullPropagationOption handleNullPropagation = HandleNullPropagationOption.Default,
71-
TimeZoneInfo timeZone = null)
83+
TimeZoneInfo timeZone = null,
84+
bool enableConstantParameterization = true)
7285
{
7386
if (options is null || options.Filter is null && options.Search is null)
7487
{
@@ -80,14 +93,14 @@ public static Expression<Func<T, bool>> ToFilterExpression<T>(this ODataQueryOpt
8093
Expression filterExpression = null;
8194
if (options.Filter is not null)
8295
{
83-
var raw = options.Filter.ToFilterExpression<T>(handleNullPropagation, timeZone);
96+
var raw = options.Filter.ToFilterExpression<T>(handleNullPropagation, timeZone, enableConstantParameterization);
8497
filterExpression = raw.Body.ReplaceParameter(raw.Parameters[0], parameter);
8598
}
8699

87100
Expression searchExpression = null;
88101
if (options.Search is not null)
89102
{
90-
var raw = options.Search.ToSearchExpression<T>(handleNullPropagation, timeZone);
103+
var raw = options.Search.ToSearchExpression<T>(handleNullPropagation, timeZone, enableConstantParameterization);
91104
searchExpression = raw.Body.ReplaceParameter(raw.Parameters[0], parameter);
92105
}
93106

AutoMapper.AspNetCore.OData.EFCore/ODataSettings.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,13 @@ public class ODataSettings
3333
/// Default is null.
3434
/// </value>
3535
public TimeZoneInfo TimeZone { get; set; }
36+
37+
/// <summary>
38+
/// Gets or sets a value indicating whether constants should be parameterized.
39+
/// </summary>
40+
/// <value>
41+
/// Default is true.
42+
/// </value>
43+
public bool EnableConstantParameterization { get; set; } = true;
3644
}
3745
}

AutoMapper.AspNetCore.OData.EFCore/QueryableExtensions.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ public static ICollection<TModel> Get<TModel, TData>(this IQueryable<TData> quer
1919
{
2020
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>(
2121
querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.False,
22-
querySettings?.ODataSettings?.TimeZone);
22+
querySettings?.ODataSettings?.TimeZone,
23+
querySettings?.ODataSettings?.EnableConstantParameterization ?? true);
2324

2425
query.ApplyOptions(mapper, filter, options, querySettings);
2526
return query.Get
@@ -36,7 +37,8 @@ public static async Task<ICollection<TModel>> GetAsync<TModel, TData>(this IQuer
3637
{
3738
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>(
3839
querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.False,
39-
querySettings?.ODataSettings?.TimeZone);
40+
querySettings?.ODataSettings?.TimeZone,
41+
querySettings?.ODataSettings?.EnableConstantParameterization ?? true);
4042
await query.ApplyOptionsAsync(mapper, filter, options, querySettings);
4143
return await query.GetAsync
4244
(
@@ -52,8 +54,9 @@ public static async Task<IQueryable<TModel>> GetQueryAsync<TModel, TData>(this I
5254
where TModel : class
5355
{
5456
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>(
55-
querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.False,
56-
querySettings?.ODataSettings?.TimeZone);
57+
querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.False,
58+
querySettings?.ODataSettings?.TimeZone,
59+
querySettings?.ODataSettings?.EnableConstantParameterization ?? true);
5760

5861
await query.ApplyOptionsAsync(mapper, filter, options, querySettings);
5962
return query.GetQueryable(mapper, options, querySettings, filter);
@@ -64,7 +67,8 @@ public static IQueryable<TModel> GetQuery<TModel, TData>(this IQueryable<TData>
6467
{
6568
Expression<Func<TModel, bool>> filter = options.ToFilterExpression<TModel>(
6669
querySettings?.ODataSettings?.HandleNullPropagation ?? HandleNullPropagationOption.False,
67-
querySettings?.ODataSettings?.TimeZone);
70+
querySettings?.ODataSettings?.TimeZone,
71+
querySettings?.ODataSettings?.EnableConstantParameterization ?? true);
6872
query.ApplyOptions(mapper, filter, options, querySettings);
6973
return query.GetQueryable(mapper, options, querySettings, filter);
7074
}

AutoMapper.OData.EFCore.Tests/GetQueryTests.cs

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,36 @@ void Test(ICollection<CoreBuilding> collection)
739739
}
740740
}
741741

742+
[Fact]
743+
public void BuildingsFilterNameDisableConstantParameterization()
744+
{
745+
string query = "/corebuilding?$filter=contains(Name, 'Two L2')";
746+
Test(GetQuery<CoreBuilding, TBuilding>(query, querySettings: new() { ODataSettings = new() { EnableConstantParameterization = false } }));
747+
748+
void Test(IQueryable<CoreBuilding> queryable)
749+
{
750+
string sqlQuery = queryable.ToQueryString();
751+
Assert.Contains("LIKE N'%Two L2%'", sqlQuery);
752+
Assert.DoesNotContain("DECLARE", sqlQuery);
753+
Assert.DoesNotContain("ESCAPE", sqlQuery);
754+
}
755+
}
756+
757+
[Fact]
758+
public void BuildingsFilterNameEnableConstantParameterization()
759+
{
760+
string query = "/corebuilding?$filter=contains(Name, 'Two L2')";
761+
Test(GetQuery<CoreBuilding, TBuilding>(query, querySettings: new() { ODataSettings = new() { EnableConstantParameterization = true } }));
762+
763+
void Test(IQueryable<CoreBuilding> queryable)
764+
{
765+
string sqlQuery = queryable.ToQueryString();
766+
Assert.DoesNotContain("LIKE N'%Two L2%'", sqlQuery);
767+
Assert.Contains("DECLARE", sqlQuery);
768+
Assert.Contains("ESCAPE", sqlQuery);
769+
}
770+
}
771+
742772
[Fact]
743773
public async void OpsTenantOrderByCountOfReference()
744774
{
@@ -1332,15 +1362,27 @@ IQueryable<TModel> DoGet(IMapper mapper)
13321362
}
13331363
}
13341364

1335-
private ICollection<TModel> Get<TModel, TData>(string query, ODataQueryOptions<TModel> options = null, QuerySettings querySettings = null) where TModel : class where TData : class
1365+
private IQueryable<TModel> GetQuery<TModel, TData>(string query, ODataQueryOptions<TModel> options = null, QuerySettings querySettings = null) where TModel : class where TData : class
13361366
{
1337-
return Get
1367+
return DoGet
13381368
(
1339-
query,
1340-
serviceProvider.GetRequiredService<MyDbContext>().Set<TData>(),
1341-
options,
1342-
querySettings
1369+
serviceProvider.GetRequiredService<IMapper>()
13431370
);
1371+
1372+
IQueryable<TModel> DoGet(IMapper mapper)
1373+
{
1374+
return serviceProvider.GetRequiredService<MyDbContext>().Set<TData>().GetQuery
1375+
(
1376+
mapper,
1377+
options ?? GetODataQueryOptions<TModel>(query),
1378+
querySettings
1379+
);
1380+
};
1381+
}
1382+
1383+
private ICollection<TModel> Get<TModel, TData>(string query, ODataQueryOptions<TModel> options = null, QuerySettings querySettings = null) where TModel : class where TData : class
1384+
{
1385+
return GetQuery<TModel, TData>(query, options, querySettings).ToList();
13441386
}
13451387

13461388
private async Task<ICollection<TModel>> GetAsync<TModel, TData>(string query,

0 commit comments

Comments
 (0)