1515
1616using System ;
1717using FluentAssertions ;
18+ using MongoDB . Bson . Serialization . Attributes ;
1819using MongoDB . Driver . Linq ;
1920using Xunit ;
2021
2122namespace MongoDB . Driver . Tests . Linq . Linq3ImplementationTests . Translators . ExpressionToAggregationExpressionTranslators
2223{
2324 public class MemberInitExpressionToAggregationExpressionTranslatorTests : Linq3IntegrationTest
2425 {
25- private readonly IMongoCollection < MyData > _collection ;
26-
27- public MemberInitExpressionToAggregationExpressionTranslatorTests ( )
26+ [ Fact ]
27+ public void Should_project_class_via_parameterless_constructor ( )
2828 {
29- _collection = CreateCollection ( LinqProvider . V3 ) ;
29+ var collection = CreateCollection ( ) ;
30+
31+ var queryable = collection . AsQueryable ( )
32+ . Select ( x => new SpawnDataClassParameterless
33+ {
34+ Identifier = x . Id ,
35+ SpawnDate = x . Date ,
36+ SpawnText = x . Text
37+ } ) ;
38+
39+ var stages = Translate ( collection , queryable ) ;
40+ AssertStages ( stages , "{ $project : { Identifier : '$_id', SpawnDate : '$Date', SpawnText : '$Text', _id : 0 } }" ) ;
41+
42+ var results = queryable . Single ( ) ;
43+
44+ results . SpawnDate . Should ( ) . Be ( new DateTime ( 2023 , 1 , 2 , 3 , 4 , 5 , DateTimeKind . Utc ) ) ;
45+ results . SpawnText . Should ( ) . Be ( "data text" ) ;
46+ results . Identifier . Should ( ) . Be ( 1 ) ;
3047 }
3148
3249 [ Fact ]
33- public void Should_project_via_parameterless_constructor ( )
50+ public void Should_project_struct_via_parameterless_constructor ( )
3451 {
35- var queryable = _collection . AsQueryable ( )
36- . Select ( x => new SpawnDataParameterless
52+ var collection = CreateCollection ( ) ;
53+
54+ var queryable = collection . AsQueryable ( )
55+ . Select ( x => new SpawnDataStructParameterless
3756 {
3857 Identifier = x . Id ,
3958 SpawnDate = x . Date ,
4059 SpawnText = x . Text
4160 } ) ;
4261
43- var stages = Translate ( _collection , queryable ) ;
62+ var stages = Translate ( collection , queryable ) ;
4463 AssertStages ( stages , "{ $project : { Identifier : '$_id', SpawnDate : '$Date', SpawnText : '$Text', _id : 0 } }" ) ;
4564
4665 var results = queryable . Single ( ) ;
@@ -51,15 +70,38 @@ public void Should_project_via_parameterless_constructor()
5170 }
5271
5372 [ Fact ]
54- public void Should_project_via_constructor ( )
73+ public void Should_project_class_via_constructor ( )
5574 {
56- var queryable = _collection . AsQueryable ( )
57- . Select ( x => new SpawnData ( x . Id , x . Date )
75+ var collection = CreateCollection ( ) ;
76+
77+ var queryable = collection . AsQueryable ( )
78+ . Select ( x => new SpawnDataClass ( x . Id , x . Date )
79+ {
80+ SpawnText = x . Text
81+ } ) ;
82+
83+ var stages = Translate ( collection , queryable ) ;
84+ AssertStages ( stages , "{ $project : { Identifier : '$_id', SpawnDate : '$Date', SpawnText : '$Text', _id : 0 } }" ) ;
85+
86+ var results = queryable . Single ( ) ;
87+
88+ results . SpawnDate . Should ( ) . Be ( new DateTime ( 2023 , 1 , 2 , 3 , 4 , 5 , DateTimeKind . Utc ) ) ;
89+ results . SpawnText . Should ( ) . Be ( "data text" ) ;
90+ results . Identifier . Should ( ) . Be ( 1 ) ;
91+ }
92+
93+ [ Fact ]
94+ public void Should_project_struct_via_constructor ( )
95+ {
96+ var collection = CreateCollection ( ) ;
97+
98+ var queryable = collection . AsQueryable ( )
99+ . Select ( x => new SpawnDataStruct ( x . Id , x . Date )
58100 {
59101 SpawnText = x . Text
60102 } ) ;
61103
62- var stages = Translate ( _collection , queryable ) ;
104+ var stages = Translate ( collection , queryable ) ;
63105 AssertStages ( stages , "{ $project : { Identifier : '$_id', SpawnDate : '$Date', SpawnText : '$Text', _id : 0 } }" ) ;
64106
65107 var results = queryable . Single ( ) ;
@@ -72,13 +114,15 @@ public void Should_project_via_constructor()
72114 [ Fact ]
73115 public void Should_project_via_constructor_with_inheritance ( )
74116 {
75- var queryable = _collection . AsQueryable ( )
117+ var collection = CreateCollection ( ) ;
118+
119+ var queryable = collection . AsQueryable ( )
76120 . Select ( x => new InheritedSpawnData ( x . Id , x . Date )
77121 {
78122 SpawnText = x . Text
79123 } ) ;
80124
81- var stages = Translate ( _collection , queryable ) ;
125+ var stages = Translate ( collection , queryable ) ;
82126 AssertStages ( stages , "{ $project : { Identifier : '$_id', SpawnDate : '$Date', SpawnText : '$Text', _id : 0 } }" ) ;
83127
84128 var results = queryable . Single ( ) ;
@@ -88,9 +132,9 @@ public void Should_project_via_constructor_with_inheritance()
88132 results . Identifier . Should ( ) . Be ( 1 ) ;
89133 }
90134
91- private IMongoCollection < MyData > CreateCollection ( LinqProvider linqProvider )
135+ private IMongoCollection < MyData > CreateCollection ( )
92136 {
93- var collection = GetCollection < MyData > ( "data" , linqProvider ) ;
137+ var collection = GetCollection < MyData > ( "data" ) ;
94138
95139 CreateCollection (
96140 collection ,
@@ -106,23 +150,70 @@ public class MyData
106150 public string Text ;
107151 }
108152
109- public class SpawnDataParameterless
153+ public class SpawnDataClassParameterless
110154 {
111155 public int Identifier ;
112156 public DateTime SpawnDate ;
113157 public string SpawnText ;
114158 }
115159
116- public class SpawnData
160+ public struct SpawnDataStructParameterless
161+ {
162+ public int Identifier ;
163+ public DateTime SpawnDate ;
164+ public string SpawnText ;
165+
166+ // this constructor is required to be able to deserialize instances of this struct
167+ [ BsonConstructor ]
168+ public SpawnDataStructParameterless ( int identifier , DateTime spawnDate , string spawnText )
169+ {
170+ Identifier = identifier ;
171+ SpawnDate = spawnDate ;
172+ SpawnText = spawnText ;
173+ }
174+ }
175+
176+ public class SpawnDataClass
177+ {
178+ public readonly int Identifier ;
179+ public DateTime SpawnDate ;
180+ private string spawnText ;
181+
182+ public SpawnDataClass ( int identifier , DateTime spawnDate )
183+ {
184+ Identifier = identifier ;
185+ SpawnDate = spawnDate ;
186+ }
187+
188+ public string SpawnText
189+ {
190+ get => spawnText ;
191+ set => spawnText = value ;
192+ }
193+ }
194+
195+ public struct SpawnDataStruct
117196 {
197+ [ BsonElement ]
118198 public readonly int Identifier ;
119199 public DateTime SpawnDate ;
120200 private string spawnText ;
121201
122- public SpawnData ( int identifier , DateTime spawnDate )
202+ // this constructor is required for the test to compile
203+ public SpawnDataStruct ( int identifier , DateTime spawnDate )
204+ {
205+ Identifier = identifier ;
206+ SpawnDate = spawnDate ;
207+ spawnText = default ;
208+ }
209+
210+ // this constructor is required to be able to deserialize instances of this struct
211+ [ BsonConstructor ]
212+ public SpawnDataStruct ( int identifier , DateTime spawnDate , string spawnText )
123213 {
124214 Identifier = identifier ;
125215 SpawnDate = spawnDate ;
216+ this . spawnText = spawnText ;
126217 }
127218
128219 public string SpawnText
@@ -132,7 +223,7 @@ public string SpawnText
132223 }
133224 }
134225
135- public class InheritedSpawnData : SpawnData
226+ public class InheritedSpawnData : SpawnDataClass
136227 {
137228 public InheritedSpawnData ( int identifier , DateTime spawnDate )
138229 : base ( identifier , spawnDate )
0 commit comments