[CSHARP-1777] Regression 2.3 driver- Nullible List Contains operator Created: 05/Oct/16  Updated: 07/Mar/17  Resolved: 06/Mar/17

Status: Closed
Project: C# Driver
Component/s: Linq
Affects Version/s: 2.3
Fix Version/s: 2.4.3

Type: Bug Priority: Major - P3
Reporter: Bret Ferrier Assignee: Robert Stam
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows


Issue Links:
Duplicate
is duplicated by CSHARP-1929 Using array in Expression Filter thro... Closed

 Description   

I have a fairly simple method shown below that worked with the 2.2.x driver but now throws an error

        public void RemoveEventsIfExists(IEnumerable<long> persistentIds)
        {
            var pIds = persistentIds.Select(x => x as long?);
            someIMongoCollection.DeleteMany(x => pIds.Contains(x.SomeNullableLongProperty));
        }

Exception Message:

Unable to cast object of type 'MongoDB.Bson.Serialization.Serializers.ImpliedImplementationInterfaceSerializer`2[System.Collections.Generic.IEnumerable`1[System.Nullable`1[System.Int64]],System.Collections.Generic.List`1[System.Nullable`1[System.Int64]]]' to type 'MongoDB.Bson.Serialization.IBsonSerializer`1[System.Int64]'.

Stack Trace:

at MongoDB.Bson.Serialization.Serializers.NullableSerializer`1.MongoDB.Bson.Serialization.IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer childSerializer)
at MongoDB.Driver.Linq.SerializerHelper.RecursiveConfigureChildSerializer(IChildSerializerConfigurable configurable, IBsonSerializer childSerializer)
at MongoDB.Driver.Linq.Processors.PipelineBindingContext.GetSerializer(Type type, Expression node)
at MongoDB.Driver.Linq.Processors.EmbeddedPipeline.EmbeddedPipelineBinder.BindNonMethodCall(Expression node)
at MongoDB.Driver.Linq.Processors.PipelineBinderBase`1.Bind(Expression node)
at MongoDB.Driver.Linq.Processors.PipelineBinderBase`1.BindPipeline(Expression node)
at MongoDB.Driver.Linq.Processors.PipelineBinderBase`1.BindMethodCall(MethodCallExpression node)
at MongoDB.Driver.Linq.Processors.PipelineBinderBase`1.Bind(Expression node)
at MongoDB.Driver.Linq.Processors.EmbeddedPipeline.EmbeddedPipelineBinder.Bind(Expression node, IBindingContext parent)
at MongoDB.Driver.Linq.Processors.SerializationBinder.BindEmbeddedPipeline(MethodCallExpression node)
at MongoDB.Driver.Linq.Processors.SerializationBinder.VisitMethodCall(MethodCallExpression node)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at MongoDB.Driver.Linq.Processors.SerializationBinder.Visit(Expression node)
at MongoDB.Driver.Linq.Translators.PredicateTranslator.Translate[TDocument](Expression`1 predicate, IBsonSerializer`1 parameterSerializer, IBsonSerializerRegistry serializerRegistry)
at MongoDB.Driver.ExpressionFilterDefinition`1.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry)
at MongoDB.Driver.MongoCollectionImpl`1.ConvertWriteModelToWriteRequest(WriteModel`1 model, Int32 index)
at System.Linq.Enumerable.<SelectIterator>d__5`2.MoveNext()
at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.BatchHelper.<FindOrderedRuns>d__8.MoveNext()
at MongoDB.Driver.Core.Misc.ReadAheadEnumerable`1.ReadAheadEnumerator.MoveNext()
at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.BatchHelper.<GetBatches>d__6.MoveNext()
at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.Execute(IWriteBinding binding, CancellationToken cancellationToken)
at MongoDB.Driver.OperationExecutor.ExecuteWriteOperation[TResult](IWriteBinding binding, IWriteOperation`1 operation, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.ExecuteWriteOperation[TResult](IWriteOperation`1 operation, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)
at MongoDB.Driver.MongoCollectionBase`1.DeleteMany(FilterDefinition`1 filter, CancellationToken cancellationToken)
at MongoDB.Driver.IMongoCollectionExtensions.DeleteMany[TDocument](IMongoCollection`1 collection, Expression`1 filter, CancellationToken cancellationToken)
at MyLibrary.RemoveEventsIfExists(IEnumerable`1 persistentIds) in C:\dev\MyRepo.cs:line 1266



 Comments   
Comment by Robert Stam [ 06/Mar/17 ]

The change made in 2.3 was intended to address a particular scenario but was inadvertently being applied in other scenarios were it did not apply (and therefore ended up throwing an exception).

The fix made for 2.4.3 is a low impact change which basically verifies in advance that an exception won't be thrown before applying the new behavior, and falls back to pre 2.3 behavior for scenarios were an exception would have been thrown by the new code.

It's possible a more comprehensive fix might be warranted at some future time. That might depend partly on whether any further bugs are reported.

Comment by Githook User [ 06/Mar/17 ]

Author:

{u'username': u'rstam', u'name': u'rstam', u'email': u'robert@robertstam.org'}

Message: CSHARP-1777: Fix regression in filter builder with Contains in an expression.
Branch: master
https://github.com/mongodb/mongo-csharp-driver/commit/1ac46bd68049a5e002f4f2632cf84ecfe5f8c505

Comment by Robert Stam [ 02/Mar/17 ]

I am able to reproduce this using this minimal test program:

namespace TestCSharp1777
{
    public enum E { A, B }
 
    public class C
    {
        public int Id;
        [BsonRepresentation(BsonType.String)]
        public E? P;
    }
 
    public static class Program
    {
        public static void Main(string[] args)
        {
            var client = new MongoClient("mongodb://localhost");
            var database = client.GetDatabase("test");
            var collection = database.GetCollection<C>("test");
 
            var persistentIds = (IEnumerable<E>)(new E[] { E.A, E.B });
            var pIds = persistentIds.Select(x => x as E?);
            var query = collection.Find(x => pIds.Contains(x.P)).ToString();
            Console.WriteLine(query);
        }
    }
}

With 2.2.4 the output is:

find({ "P" : { "$in" : ["A", "B"] } })

With 2.3+ an exception is thrown.

Generated at Wed Feb 07 21:40:40 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.