private IBsonSerializer BuildProjectedSerializer(ProjectionMapping mapping) { // We are building a serializer specifically for a projected type based // on serialization information collected from other serializers. // We cannot cache this in the serializer registry because the compiler reuses // the same anonymous type definition in different contexts as long as they // are structurally equatable. As such, it might be that two different queries // projecting the same shape might need to be deserialized differently. var classMap = BuildClassMap(mapping.Expression.Type, mapping); var mappedParameters = mapping.Members .Where(x => x.Parameter != null) .OrderBy(x => x.Parameter.Position) .Select(x => x.Member) .ToList(); if (mappedParameters.Count > 0) { classMap.MapConstructor(mapping.Constructor) .SetArguments(mappedParameters); } var serializerType = typeof(BsonClassMapSerializer <>).MakeGenericType(mapping.Expression.Type); return((IBsonSerializer)Activator.CreateInstance(serializerType, classMap.Freeze())); }
private BsonClassMap BuildClassMap(Type type, ProjectionMapping mapping) { if (type == null || type == typeof(object)) { return(null); } var baseClassMap = BuildClassMap(type.GetTypeInfo().BaseType, mapping); if (baseClassMap != null) { baseClassMap.Freeze(); } var classMap = new BsonClassMap(type, baseClassMap); foreach (var memberMapping in mapping.Members.Where(x => x.Member.DeclaringType == type)) { var serializationExpression = memberMapping.Expression as SerializationExpression; if (serializationExpression == null) { var serializer = Build(memberMapping.Expression); serializationExpression = new FieldExpression( memberMapping.Member.Name, serializer, memberMapping.Expression); } var memberMap = classMap.MapMember(memberMapping.Member) .SetSerializer(serializationExpression.Serializer) .SetElementName(memberMapping.Member.Name); if (classMap.IdMemberMap == null && serializationExpression is GroupingKeyExpression) { classMap.SetIdMember(memberMap); } } return(classMap); }