Skip to content

Commit 8de67a7

Browse files
habbesxuzhg
authored andcommitted
Fix EFCore memory lean when query contains collection constant, PR 2172
1 parent 4d8c2ba commit 8de67a7

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

src/Microsoft.AspNet.OData.Shared/Query/Expressions/ExpressionBinderBase.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1359,7 +1359,12 @@ public virtual Expression BindCollectionConstantNode(CollectionConstantNode node
13591359
castedList.Add(member);
13601360
}
13611361

1362-
return Expression.Constant(castedList);
1362+
if (QuerySettings.EnableConstantParameterization)
1363+
{
1364+
return LinqParameterContainer.Parameterize(listType, castedList);
1365+
}
1366+
1367+
return Expression.Constant(castedList, listType);
13631368
}
13641369

13651370
private Expression BindCastSingleValue(SingleValueFunctionCallNode node)

test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/Expressions/FilterBinderTests.cs

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,8 +1642,8 @@ public void EnumInExpression()
16421642
"$it => System.Collections.Generic.List`1[Microsoft.AspNet.OData.Test.Common.Types.SimpleEnum].Contains($it.SimpleEnumProp)");
16431643
Expression<Func<DataTypes, bool>> expression = result.WithNullPropagation;
16441644

1645-
// expression tree is guaranteed by expression string above
1646-
var values = (IList<SimpleEnum>)((ConstantExpression)((MethodCallExpression) expression.Body).Arguments[0]).Value;
1645+
var memberAccess = (MemberExpression)((MethodCallExpression)expression.Body).Arguments[0];
1646+
var values = (IList<SimpleEnum>)ExpressionBinderBase.ExtractParameterizedConstant(memberAccess);
16471647
Assert.Equal(new[] {SimpleEnum.First, SimpleEnum.Second}, values);
16481648
}
16491649

@@ -1663,8 +1663,8 @@ public void EnumInExpression_NullableEnum_WithNullable()
16631663
"$it => System.Collections.Generic.List`1[System.Nullable`1[Microsoft.AspNet.OData.Test.Common.Types.SimpleEnum]].Contains($it.NullableSimpleEnumProp)");
16641664
Expression<Func<DataTypes, bool>> expression = result.WithNullPropagation;
16651665

1666-
// expression tree is guaranteed by expression string above
1667-
var values = (IList<SimpleEnum?>)((ConstantExpression)((MethodCallExpression) expression.Body).Arguments[0]).Value;
1666+
var memberAccess = (MemberExpression)((MethodCallExpression)expression.Body).Arguments[0];
1667+
var values = (IList<SimpleEnum?>)ExpressionBinderBase.ExtractParameterizedConstant(memberAccess);
16681668
Assert.Equal(new SimpleEnum?[] {SimpleEnum.First, SimpleEnum.Second}, values);
16691669
}
16701670

@@ -1676,8 +1676,8 @@ public void EnumInExpression_NullableEnum_WithNullValue()
16761676
"$it => System.Collections.Generic.List`1[System.Nullable`1[Microsoft.AspNet.OData.Test.Common.Types.SimpleEnum]].Contains($it.NullableSimpleEnumProp)");
16771677
Expression<Func<DataTypes, bool>> expression = result.WithNullPropagation;
16781678

1679-
// expression tree is guaranteed by expression string above
1680-
var values = (IList<SimpleEnum?>)((ConstantExpression)((MethodCallExpression) expression.Body).Arguments[0]).Value;
1679+
var memberAccess = (MemberExpression)((MethodCallExpression)expression.Body).Arguments[0];
1680+
var values = (IList<SimpleEnum?>)ExpressionBinderBase.ExtractParameterizedConstant(memberAccess);
16811681
Assert.Equal(new SimpleEnum?[] {SimpleEnum.First, null}, values);
16821682
}
16831683

@@ -2875,6 +2875,50 @@ public void Constants_Are_Not_Parameterized_IfDisabled()
28752875
Assert.Equal("$it => ($it.ProductName == \"1\")", (filters.WithoutNullPropagation as Expression).ToString());
28762876
}
28772877

2878+
[Fact]
2879+
public void CollectionConstants_Are_Parameterized()
2880+
{
2881+
var result = VerifyQueryDeserialization("ProductName in ('Prod1', 'Prod2')",
2882+
"$it => System.Collections.Generic.List`1[System.String].Contains($it.ProductName)");
2883+
2884+
Expression<Func<Product, bool>> expression = result.WithNullPropagation;
2885+
2886+
var memberAccess = (MemberExpression)((MethodCallExpression)expression.Body).Arguments[0];
2887+
var values = (IList<string>)ExpressionBinderBase.ExtractParameterizedConstant(memberAccess);
2888+
Assert.Equal(new[] { "Prod1", "Prod2" }, values);
2889+
}
2890+
2891+
[Fact]
2892+
public void CollectionConstants_Are_Not_Parameterized_If_Disabled()
2893+
{
2894+
var result = VerifyQueryDeserialization("ProductName in ('Prod1', 'Prod2')",
2895+
"$it => System.Collections.Generic.List`1[System.String].Contains($it.ProductName)",
2896+
settingsCustomizer: (settings) =>
2897+
{
2898+
settings.EnableConstantParameterization = false;
2899+
});
2900+
2901+
Expression<Func<Product, bool>> expression = result.WithNullPropagation;
2902+
var values = (IList<string>)((ConstantExpression)((MethodCallExpression)expression.Body).Arguments[0]).Value;
2903+
Assert.Equal(new[] { "Prod1", "Prod2" }, values);
2904+
}
2905+
2906+
[Fact]
2907+
public void CollectionConstants_OfEnums_Are_Not_Parameterized_If_Disabled()
2908+
{
2909+
var result = VerifyQueryDeserialization<DataTypes>(
2910+
"SimpleEnumProp in ('First', 'Second')",
2911+
"$it => System.Collections.Generic.List`1[Microsoft.AspNet.OData.Test.Common.Types.SimpleEnum].Contains($it.SimpleEnumProp)",
2912+
settingsCustomizer: (settings) =>
2913+
{
2914+
settings.EnableConstantParameterization = false;
2915+
});
2916+
2917+
Expression<Func<DataTypes, bool>> expression = result.WithNullPropagation;
2918+
var values = (IList<SimpleEnum>)((ConstantExpression)((MethodCallExpression)expression.Body).Arguments[0]).Value;
2919+
Assert.Equal(new[] { SimpleEnum.First, SimpleEnum.Second }, values);
2920+
}
2921+
28782922
[Fact]
28792923
public void FilterByDynamicProperty()
28802924
{

0 commit comments

Comments
 (0)