Skip to content

Commit 7746b0f

Browse files
committed
CSHARP-4658: NullReferenceException when using certain projections.
1 parent 513d0ce commit 7746b0f

File tree

2 files changed

+112
-13
lines changed

2 files changed

+112
-13
lines changed

src/MongoDB.Driver/Linq/Linq3Implementation/Misc/PartialEvaluator.cs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -190,21 +190,17 @@ public override Expression Visit(Expression expression)
190190
protected override Expression VisitMemberInit(MemberInitExpression node)
191191
{
192192
// Bindings must be visited before NewExpression
193-
foreach (var binding in node.Bindings)
194-
{
195-
switch (binding.BindingType)
196-
{
197-
case MemberBindingType.Assignment:
198-
var memberAssignment = (MemberAssignment)binding;
199-
base.Visit(memberAssignment.Expression);
200-
break;
193+
Visit(node.Bindings, VisitMemberBinding);
201194

202-
default:
203-
throw new InvalidOperationException($"Unexpected binding type: {binding.BindingType}.");
204-
}
195+
if (_cannotBeEvaluated)
196+
{
197+
// visit only the arguments if any MemberBindings cannot be partially evaluated
198+
Visit(node.NewExpression.Arguments);
199+
}
200+
else
201+
{
202+
Visit(node.NewExpression);
205203
}
206-
207-
base.Visit(node.NewExpression);
208204

209205
return node;
210206
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/* Copyright 2010-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System.Linq;
17+
using MongoDB.Driver.Linq;
18+
using MongoDB.TestHelpers.XunitExtensions;
19+
using Xunit;
20+
21+
namespace MongoDB.Driver.Tests.Linq.Linq3ImplementationTests.Jira
22+
{
23+
public class CSharp4658Tests : Linq3IntegrationTest
24+
{
25+
[Theory]
26+
[ParameterAttributeData]
27+
public void Select_new_Model_should_work(
28+
[Values(LinqProvider.V2, LinqProvider.V3)] LinqProvider linqProvider)
29+
{
30+
var collection = GetCollection(linqProvider);
31+
32+
var queryable = collection.AsQueryable()
33+
.GroupBy(x => x.Name)
34+
.Select(x =>
35+
new Model
36+
{
37+
NotId = string.Empty,
38+
Name = x.Key
39+
});
40+
41+
var stages = Translate(collection, queryable);
42+
AssertStages(
43+
stages,
44+
"{ $group : { _id : '$Name' } }",
45+
"{ $project : { NotId : '', Name : '$_id', _id : 0 } }");
46+
}
47+
48+
[Theory]
49+
[ParameterAttributeData]
50+
public void Project_new_ModelAggregated_should_work(
51+
[Values(LinqProvider.V2, LinqProvider.V3)] LinqProvider linqProvider)
52+
{
53+
var collection = GetCollection(linqProvider);
54+
55+
var aggregate = collection.Aggregate()
56+
.Group(
57+
x => "",
58+
g => new { Count = g.Count()}
59+
)
60+
.Project(
61+
x => new ModelAggregated
62+
{
63+
NotId = string.Empty,
64+
Count = x.Count
65+
});
66+
67+
var stages = Translate(collection, aggregate);
68+
if (linqProvider == LinqProvider.V2)
69+
{
70+
AssertStages(
71+
stages,
72+
"{ $group : { _id : '', Count : { $sum : 1 } } }",
73+
"{ $project : { NotId : '', Count : '$Count', _id : 0 } }");
74+
}
75+
else
76+
{
77+
AssertStages(
78+
stages,
79+
"{ $group : { _id : '', __agg0 : { $sum : 1 } } }",
80+
"{ $project : { Count : '$__agg0', _id : 0 } }",
81+
"{ $project : { NotId : '', Count : 1, _id : 0 } }");
82+
}
83+
}
84+
85+
private IMongoCollection<Model> GetCollection(LinqProvider linqProvider)
86+
{
87+
var collection = GetCollection<Model>("test", linqProvider);
88+
return collection;
89+
}
90+
91+
private class Model
92+
{
93+
public string NotId { get; set; }
94+
public string Name { get; set; }
95+
}
96+
97+
private class ModelAggregated
98+
{
99+
public string NotId { get; set; }
100+
public int Count { get; set; }
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)