Hello,
PullFilter on Guid array works fine with LinqProvider.V2, but V3 throws exception:
System.InvalidCastException
HResult=0x80004002
Message=Unable to cast object of type 'MongoDB.Bson.Serialization.Serializers.GuidSerializer' to type 'MongoDB.Bson.Serialization.IBsonDocumentSerializer'.
Source=MongoDB.Driver
StackTrace:
at MongoDB.Driver.Linq.Linq3Implementation.Translators.TranslationContext.Create(Expression expression, IBsonSerializer serializer, TranslationContextData data)
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.PullUpdateDefinition`2.Render(IBsonSerializer`1 documentSerializer, IBsonSerializerRegistry serializerRegistry, LinqProvider linqProvider)
at MongoDB.Driver.MongoCollectionImpl`1.ConvertWriteModelToWriteRequest(WriteModel`1 model, Int32 index)
at System.Linq.Enumerable.<SelectIterator>d__229`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation..ctor(CollectionNamespace collectionNamespace, IEnumerable`1 requests, MessageEncoderSettings messageEncoderSettings)
at MongoDB.Driver.MongoCollectionImpl`1.CreateBulkWriteOperation(IClientSessionHandle session, IEnumerable`1 requests, BulkWriteOptions options)
at MongoDB.Driver.MongoCollectionImpl`1.<BulkWriteAsync>d__33.MoveNext()
at MongoDB.Driver.MongoCollectionImpl`1.<UsingImplicitSessionAsync>d__115`1.MoveNext()
at MongoDB.Driver.MongoCollectionBase`1.<UpdateOneAsync>d__113.MoveNext()
at Program.<<Main>$>d__0.MoveNext() in C:\Users\jn\source\repos\MongoDbLinqProvider3PullProblem\MongoDbLinqProvider3PullFromGuidArrayProblem\Program.cs:line 40
at Program.<Main>(String[] args)
Demonstrated by this code:
using MongoDB.Driver;
using MongoDB.Driver.Linq;
var settings = new MongoClientSettings { LinqProvider = LinqProvider.V3 };
var client = new MongoClient(settings);
var db = client.GetDatabase("test");
var coll = db.GetCollection<Foo>("Foos");
var fooId = Guid.Parse("{9DF3D93D-9989-42BB-B54E-A3AB603CE05E}");
var barId1 = Guid.Parse("{B1554855-6B5A-4AD5-AE2F-33567A057A39}");
var barId2 = Guid.Parse("{90D62CD4-12DF-49D9-A3C9-62C00EFAB23A}");
var foo = new Foo
{
Id = fooId,
BarRefs =
{
barId1,
barId2,
},
};
var barRefsToRemove = new List<Guid>
{
barId1,
};
var fooIdFilter = Builders<Foo>.Filter.Eq(x => x.Id, fooId);
await coll.DeleteOneAsync(fooIdFilter);
await coll.InsertOneAsync(foo);
//var update = Builders<Foo>.Update.Pull(x => x.BarRefs, barId1);
var update = Builders<Foo>.Update.PullFilter(x => x.BarRefs, y => barRefsToRemove.Contains(y));
var query = await coll.UpdateOneAsync(fooIdFilter, update);
record Foo
{
public Guid Id { get; set; }
public List<Guid> BarRefs { get; set; } = [];
};
Using Pull (singled value instead of filter), works fine (commented out).
So does wrapping the Guids in a wrapper class, presumably because the array is then a document array instead of a Guid array:
using MongoDB.Driver;
using MongoDB.Driver.Linq;
var settings = new MongoClientSettings { LinqProvider = LinqProvider.V3 };
var client = new MongoClient(settings);
var db = client.GetDatabase("test");
var coll = db.GetCollection<Foo>("Foos");
var fooId = Guid.Parse("{9DF3D93D-9989-42BB-B54E-A3AB603CE05E}");
var barId1 = Guid.Parse("{B1554855-6B5A-4AD5-AE2F-33567A057A39}");
var barId2 = Guid.Parse("{90D62CD4-12DF-49D9-A3C9-62C00EFAB23A}");
var foo = new Foo
{
Id = fooId,
BarRefs =
{
GuidIdWrapper.FromId(barId1),
GuidIdWrapper.FromId(barId2),
},
};
var barRefsToRemove = new List<Guid>
{
barId1,
};
var fooIdFilter = Builders<Foo>.Filter.Eq(x => x.Id, fooId);
await coll.DeleteOneAsync(fooIdFilter);
await coll.InsertOneAsync(foo);
var update = Builders<Foo>.Update.PullFilter(x => x.BarRefs, y => barRefsToRemove.Contains(y.Id));
var query = await coll.UpdateOneAsync(fooIdFilter, update);
record Foo
{
public Guid Id { get; set; }
public List<GuidIdWrapper> BarRefs { get; set; } = [];
};
class GuidIdWrapper
{
public Guid Id { get; set; }
public static GuidIdWrapper FromId(Guid id)
{
return new GuidIdWrapper
{
Id = id,
};
}
}
Would of course rather avoid having to migrate existing documents to accommodate this.