@@ -28,25 +28,28 @@ internal static class MemberInitExpressionToAggregationExpressionTranslator
28
28
{
29
29
public static AggregationExpression Translate ( TranslationContext context , MemberInitExpression expression )
30
30
{
31
- var computedFields = new List < AstComputedField > ( ) ;
32
- var classMap = CreateClassMap ( expression . Type ) ;
33
-
34
31
var newExpression = expression . NewExpression ;
35
32
var constructorInfo = newExpression . Constructor ;
36
- var constructorParameters = constructorInfo . GetParameters ( ) ;
37
33
var constructorArguments = newExpression . Arguments ;
38
- var memberNames = new string [ constructorParameters . Length ] ;
39
- for ( var i = 0 ; i < constructorParameters . Length ; i ++ )
40
- {
41
- var constructorParameter = constructorParameters [ i ] ;
42
- var memberMap = FindMatchingMemberMap ( expression , classMap , constructorParameter ) ;
43
34
44
- var argumentExpression = constructorArguments [ i ] ;
45
- var argumentTranslation = ExpressionToAggregationExpressionTranslator . Translate ( context , argumentExpression ) ;
46
- computedFields . Add ( AstExpression . ComputedField ( memberMap . ElementName , argumentTranslation . Ast ) ) ;
35
+ var classMap = CreateClassMap ( expression . Type , constructorInfo , out var creatorMap ) ;
36
+ var creatorMapParameters = creatorMap . Arguments ? . ToArray ( ) ;
37
+ if ( constructorInfo . GetParameters ( ) . Length > 0 && creatorMapParameters == null )
38
+ {
39
+ throw new ExpressionNotSupportedException ( expression , because : $ "couldn't find matching properties for constructor parameters.") ;
40
+ }
47
41
48
- memberMap . SetSerializer ( argumentTranslation . Serializer ) ;
49
- memberNames [ i ] = memberMap . MemberName ;
42
+ var computedFields = new List < AstComputedField > ( ) ;
43
+ for ( var i = 0 ; i < creatorMapParameters . Length ; i ++ )
44
+ {
45
+ var creatorMapParameter = creatorMapParameters [ i ] ;
46
+ var constructorArgumentExpression = constructorArguments [ i ] ;
47
+ var constructorArgumentTranslation = ExpressionToAggregationExpressionTranslator . Translate ( context , constructorArgumentExpression ) ;
48
+ var constructorArgumentType = constructorArgumentExpression . Type ;
49
+ var constructorArgumentSerializer = constructorArgumentTranslation . Serializer ?? BsonSerializer . LookupSerializer ( constructorArgumentType ) ;
50
+ var memberMap = EnsureMemberMap ( expression , classMap , creatorMapParameter ) ;
51
+ memberMap . SetSerializer ( constructorArgumentSerializer ) ;
52
+ computedFields . Add ( AstExpression . ComputedField ( memberMap . ElementName , constructorArgumentTranslation . Ast ) ) ;
50
53
}
51
54
52
55
foreach ( var binding in expression . Bindings )
@@ -63,48 +66,69 @@ public static AggregationExpression Translate(TranslationContext context, Member
63
66
}
64
67
65
68
var ast = AstExpression . ComputedDocument ( computedFields ) ;
66
-
67
- classMap . MapConstructor ( constructorInfo , memberNames ) ;
68
69
classMap . Freeze ( ) ;
69
70
var serializerType = typeof ( BsonClassMapSerializer < > ) . MakeGenericType ( expression . Type ) ;
70
71
var serializer = ( IBsonSerializer ) Activator . CreateInstance ( serializerType , classMap ) ;
71
72
72
73
return new AggregationExpression ( expression , ast , serializer ) ;
73
74
}
74
75
75
- private static BsonClassMap CreateClassMap ( Type classType )
76
+ private static BsonClassMap CreateClassMap ( Type classType , ConstructorInfo constructorInfo , out BsonCreatorMap creatorMap )
76
77
{
77
78
BsonClassMap baseClassMap = null ;
78
79
if ( classType . BaseType != null )
79
80
{
80
- baseClassMap = CreateClassMap ( classType . BaseType ) ;
81
+ baseClassMap = CreateClassMap ( classType . BaseType , null , out _ ) ;
81
82
}
82
83
83
84
var classMapType = typeof ( BsonClassMap < > ) . MakeGenericType ( classType ) ;
84
- var constructorInfo = classMapType . GetConstructor ( new Type [ ] { typeof ( BsonClassMap ) } ) ;
85
- var classMap = ( BsonClassMap ) constructorInfo . Invoke ( new object [ ] { baseClassMap } ) ;
85
+ var classMapConstructorInfo = classMapType . GetConstructor ( new Type [ ] { typeof ( BsonClassMap ) } ) ;
86
+ var classMap = ( BsonClassMap ) classMapConstructorInfo . Invoke ( new object [ ] { baseClassMap } ) ;
87
+ if ( constructorInfo != null )
88
+ {
89
+ creatorMap = classMap . MapConstructor ( constructorInfo ) ;
90
+ }
91
+ else
92
+ {
93
+ creatorMap = null ;
94
+ }
95
+
86
96
classMap . AutoMap ( ) ;
87
97
classMap . IdMemberMap ? . SetElementName ( "_id" ) ; // normally happens when Freeze is called but we need it sooner here
88
98
89
99
return classMap ;
90
100
}
91
101
92
- private static BsonMemberMap FindMatchingMemberMap ( Expression expression , BsonClassMap classMap , ParameterInfo parameterInfo )
102
+ private static BsonMemberMap EnsureMemberMap ( Expression expression , BsonClassMap classMap , MemberInfo creatorMapParameter )
93
103
{
94
- foreach ( var memberMap in classMap . DeclaredMemberMaps )
104
+ var declaringClassMap = classMap ;
105
+ while ( declaringClassMap . ClassType != creatorMapParameter . DeclaringType )
95
106
{
96
- if ( memberMap . MemberType == parameterInfo . ParameterType && memberMap . MemberName . Equals ( parameterInfo . Name , StringComparison . OrdinalIgnoreCase ) )
107
+ declaringClassMap = declaringClassMap . BaseClassMap ;
108
+
109
+ if ( declaringClassMap == null )
97
110
{
98
- return memberMap ;
111
+ throw new ExpressionNotSupportedException ( expression , because : $ "couldn't find matching property for constructor parameter: { creatorMapParameter . Name } " ) ;
99
112
}
100
113
}
101
114
102
- if ( classMap . BaseClassMap != null )
115
+ foreach ( var memberMap in declaringClassMap . DeclaredMemberMaps )
103
116
{
104
- return FindMatchingMemberMap ( expression , classMap . BaseClassMap , parameterInfo ) ;
117
+ if ( MemberMapMatchesCreatorMapParameter ( memberMap , creatorMapParameter ) )
118
+ {
119
+ return memberMap ;
120
+ }
105
121
}
106
122
107
- throw new ExpressionNotSupportedException ( expression , because : $ "can't find matching property for constructor parameter : { parameterInfo . Name } ") ;
123
+ return declaringClassMap . MapMember ( creatorMapParameter ) ;
124
+
125
+ static bool MemberMapMatchesCreatorMapParameter ( BsonMemberMap memberMap , MemberInfo creatorMapParameter )
126
+ {
127
+ var memberInfo = memberMap . MemberInfo ;
128
+ return
129
+ memberInfo . MemberType == creatorMapParameter . MemberType &&
130
+ memberInfo . Name . Equals ( creatorMapParameter . Name , StringComparison . OrdinalIgnoreCase ) ;
131
+ }
108
132
}
109
133
110
134
private static BsonMemberMap FindMemberMap ( Expression expression , BsonClassMap classMap , string memberName )
0 commit comments