Summary
I created a custom Id type that wraps an integer. I implemented the equality operators for this type. The problem is, when I want to filter in mongoDB with linq and the expression includes this custom operator, the expression translator throws an error.
MongoDB driver version 2.19.0, .NET version 7.0
How to Reproduce
Code:
using MongoDB.Bson.Serialization; using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver; int idToFind = 5; var filter = Builders<MyDocument>.Filter.Where(x => x.Id == idToFind); var renderedFilter = filter.Render(BsonSerializer.LookupSerializer<MyDocument>(), BsonSerializer.SerializerRegistry); Console.WriteLine(renderedFilter); public class MyDocument { public MyId Id { get; set; } public string Name { get; set; } } [BsonSerializer(typeof(MyIdSerializer))] public class MyId { public MyId(int id) { Id = id; } public int Id { get; } public static bool operator ==(int id, MyId other) => id == other.Id; public static bool operator ==(MyId id, int other) => id.Id == other; public static bool operator !=(int id, MyId other) => !(id == other); public static bool operator !=(MyId id, int other) => !(id == other); } public class MyIdSerializer : SerializerBase<MyId> { public override MyId Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { return new MyId(context.Reader.ReadInt32()); } public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, MyId value) { context.Writer.WriteInt32(value.Id); } }
Exception:
Unhandled exception. System.InvalidCastException: Unable to cast object of type 'System.Int32' to type 'MyId'. at MongoDB.Bson.Serialization.Serializers.SerializerBase`1.MongoDB.Bson.Serialization.IBsonSerializer.Serialize(BsonSerializationContext context, BsonSerializationArgs args, Object value) at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Serialize(IBsonSerializer serializer, BsonSerializationContext context, Object value) at MongoDB.Driver.Linq.Linq3Implementation.Misc.SerializationHelper.SerializeValue(IBsonSerializer serializer, Object value) at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionTranslators.ComparisonExpressionToFilterTranslator.Translate(TranslationContext context, BinaryExpression expression) at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.TranslateUsingQueryOperators(TranslationContext context, Expression expression) at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.Translate(TranslationContext context, Expression expression, Boolean exprOk) at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.TranslateLambda(TranslationContext context, LambdaExpression lambdaExpression, IBsonSerializer parameterSerializer, Boolean asRoot) at MongoDB.Driver.Linq.Linq3Implementation.LinqProviderAdapterV3.TranslateExpressionToFilter[TDocument](Expression`1 expression, IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry) at MongoDB.Driver.ExpressionFilterDefinition`1.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider) at MongoDB.Driver.FilterDefinition`1.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry) at Program.<Main>$(String[] args) in C:\src\MongoTest\MongoTest\Program.cs:line 9
Additional Background
The issue is probably in ComparisonExpressionToFilterTranslator. It tries to use the serializer of the leftExpression for serializing the right operand:
var field = ExpressionToFilterFieldTranslator.Translate(context, leftExpression); var serializedComparand = SerializationHelper.SerializeValue(field.Serializer, comparand); return AstFilter.Compare(field, comparisonOperator, serializedComparand);