Skip to content

Commit 4057647

Browse files
rstamdnickless
authored andcommitted
CSHARP-2113: Support LINQ queries against interfaces..
1 parent a9c3fe6 commit 4057647

File tree

2 files changed

+188
-1
lines changed

2 files changed

+188
-1
lines changed

src/MongoDB.Bson/Serialization/Serializers/DiscriminatedInterfaceSerializer.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,24 @@ namespace MongoDB.Bson.Serialization.Serializers
2323
/// Represents a serializer for Interfaces.
2424
/// </summary>
2525
/// <typeparam name="TInterface">The type of the interface.</typeparam>
26-
public class DiscriminatedInterfaceSerializer<TInterface> : SerializerBase<TInterface> // where TInterface is an interface
26+
public class DiscriminatedInterfaceSerializer<TInterface> : SerializerBase<TInterface>, IBsonDocumentSerializer // where TInterface is an interface
2727
{
28+
#region static
29+
private static IBsonSerializer<TInterface> CreateInterfaceSerializer()
30+
{
31+
var classMapDefinition = typeof(BsonClassMap<>);
32+
var classMapType = classMapDefinition.MakeGenericType(typeof(TInterface));
33+
var classMap = (BsonClassMap)Activator.CreateInstance(classMapType);
34+
classMap.AutoMap();
35+
classMap.Freeze();
36+
return new BsonClassMapSerializer<TInterface>(classMap);
37+
}
38+
#endregion
39+
2840
// private fields
2941
private readonly Type _interfaceType;
3042
private readonly IDiscriminatorConvention _discriminatorConvention;
43+
private readonly IBsonSerializer<TInterface> _interfaceSerializer;
3144
private readonly IBsonSerializer<object> _objectSerializer;
3245

3346
// constructors
@@ -46,6 +59,18 @@ public DiscriminatedInterfaceSerializer()
4659
/// <exception cref="System.ArgumentException">interfaceType</exception>
4760
/// <exception cref="System.ArgumentNullException">interfaceType</exception>
4861
public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorConvention)
62+
: this(discriminatorConvention, CreateInterfaceSerializer())
63+
{
64+
}
65+
66+
/// <summary>
67+
/// Initializes a new instance of the <see cref="DiscriminatedInterfaceSerializer{TInterface}" /> class.
68+
/// </summary>
69+
/// <param name="discriminatorConvention">The discriminator convention.</param>
70+
/// <param name="interfaceSerializer">The interface serializer (necessary to support LINQ queries).</param>
71+
/// <exception cref="System.ArgumentException">interfaceType</exception>
72+
/// <exception cref="System.ArgumentNullException">interfaceType</exception>
73+
public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorConvention, IBsonSerializer<TInterface> interfaceSerializer)
4974
{
5075
var interfaceTypeInfo = typeof(TInterface).GetTypeInfo();
5176
if (!interfaceTypeInfo.IsInterface)
@@ -57,6 +82,7 @@ public DiscriminatedInterfaceSerializer(IDiscriminatorConvention discriminatorCo
5782
_interfaceType = typeof(TInterface);
5883
_discriminatorConvention = discriminatorConvention;
5984
_objectSerializer = new ObjectSerializer(_discriminatorConvention);
85+
_interfaceSerializer = interfaceSerializer;
6086
}
6187

6288
// public methods
@@ -110,5 +136,17 @@ public override void Serialize(BsonSerializationContext context, BsonSerializati
110136
_objectSerializer.Serialize(context, args, value);
111137
}
112138
}
139+
140+
/// <inheritdoc/>
141+
public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
142+
{
143+
if (_interfaceSerializer is IBsonDocumentSerializer documentSerializer)
144+
{
145+
return documentSerializer.TryGetMemberSerializationInfo(memberName, out serializationInfo);
146+
}
147+
148+
serializationInfo = null;
149+
return false;
150+
}
113151
}
114152
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
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 FluentAssertions;
18+
using MongoDB.Driver.Linq;
19+
using Xunit;
20+
21+
namespace MongoDB.Driver.Tests.Linq.Linq3ImplementationTests.Jira
22+
{
23+
public class CSharp2113Tests : Linq3IntegrationTest
24+
{
25+
[Fact]
26+
public void Query1_should_work()
27+
{
28+
var collection = CreateDocumentCollection();
29+
30+
var queryable = collection
31+
.AsQueryable()
32+
.Where(x => x.X == 1);
33+
34+
var stages = Translate(collection, queryable);
35+
AssertStages(stages, "{ $match : { X : 1 } }");
36+
37+
var results = queryable.ToList();
38+
results.Select(x => x.Id).Should().Equal(1);
39+
}
40+
41+
[Fact]
42+
public void Query2_should_work()
43+
{
44+
var collection = CreateDocumentCollection();
45+
46+
var queryable = collection
47+
.AsQueryable()
48+
.Where(x => x.Inner.Y == 1);
49+
50+
var stages = Translate(collection, queryable);
51+
AssertStages(stages, "{ $match : { 'Inner.Y' : 1 } }");
52+
53+
var results = queryable.ToList();
54+
results.Select(x => x.Id).Should().Equal(1);
55+
}
56+
57+
[Fact]
58+
public void Query3_should_work()
59+
{
60+
var collection = CreateIDocumentCollection();
61+
62+
var queryable = collection
63+
.AsQueryable()
64+
.Where(x => x.X == 1);
65+
66+
var stages = Translate(collection, queryable);
67+
AssertStages(stages, "{ $match : { X : 1 } }");
68+
69+
var results = queryable.ToList();
70+
results.Select(x => x.Id).Should().Equal(1);
71+
}
72+
73+
[Fact]
74+
public void Query4_should_work()
75+
{
76+
var collection = CreateIDocumentCollection();
77+
78+
var queryable = collection
79+
.AsQueryable()
80+
.Where(x => x.Inner.Y == 1);
81+
82+
var stages = Translate(collection, queryable);
83+
AssertStages(stages, "{ $match : { 'Inner.Y' : 1 } }");
84+
85+
var results = queryable.ToList();
86+
results.Select(x => x.Id).Should().Equal(1);
87+
}
88+
89+
private IMongoCollection<Document> CreateDocumentCollection()
90+
{
91+
var collection = GetCollection<Document>();
92+
93+
CreateCollection(
94+
collection,
95+
new Document { Id = 1, X = 1, Inner = new Inner { Y = 1 } },
96+
new Document { Id = 2, X = 2, Inner = new Inner { Y = 2 } });
97+
98+
return collection;
99+
}
100+
101+
private IMongoCollection<IDocument> CreateIDocumentCollection()
102+
{
103+
var collection = GetCollection<IDocument>();
104+
105+
CreateCollection(
106+
collection,
107+
new DocumentWithInterface { Id = 1, X = 1, Inner = new InnerWithInterface { Y = 1 } },
108+
new DocumentWithInterface { Id = 2, X = 2, Inner = new InnerWithInterface { Y = 2 } });
109+
110+
return collection;
111+
}
112+
113+
private class Document
114+
{
115+
public int Id { get; set; }
116+
public int X { get; set; }
117+
public Inner Inner { get; set; }
118+
}
119+
120+
private class Inner
121+
{
122+
public int Y { get; set; }
123+
}
124+
125+
private interface IDocument
126+
{
127+
int Id { get; set; }
128+
int X { get; set; }
129+
IInner Inner { get; set; }
130+
}
131+
132+
private interface IInner
133+
{
134+
int Y { get; set; }
135+
}
136+
137+
private class DocumentWithInterface : IDocument
138+
{
139+
public int Id { get; set; }
140+
public int X { get; set; }
141+
public IInner Inner { get; set; }
142+
}
143+
144+
public class InnerWithInterface : IInner
145+
{
146+
public int Y { get; set; }
147+
}
148+
}
149+
}

0 commit comments

Comments
 (0)