Hi!
While migrating from LinqProvider.V2 to LinqProvider.V3, I encountered the following issue. I have a custom value type UserId
, which includes explicit conversion operators for Guid
. The following query worked fine in LinqProvider.V2, but after switching to LinqProvider.V3, it throws an exception:
var user = await collection.Find(Builders<User>.Filter.In(x => (Guid)x.ExternalId, new[] { guid }))
.FirstOrDefaultAsync();
Exception:
MongoDB.Driver.Linq.ExpressionNotSupportedException : Expression not supported: Convert(x.ExternalId, Guid).
Are there any workarounds for this issue in LinqProvider.V3?
Any suggestions would be appreciated!
Full Reproduction Code:
using System;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using NUnit.Framework;
namespace MongoCases
{
[TestFixture]
public class MongoCases_Linq3_ExplicitConversion : Mongo2GoFixture
{
[Test]
public async Task Test()
{
BsonSerializer.RegisterSerializer(new UserIdBsonSerializer());
var mongoClientSettings = MongoClientSettings.FromConnectionString(ConnectionString);
mongoClientSettings.LinqProvider = LinqProvider.V3;
var mongoClient = new MongoClient(mongoClientSettings);
var db = mongoClient.GetDatabase(Guid.NewGuid().ToString()[..8]);
var collection = db.GetCollection<User>("users");
var guid = Guid.NewGuid();
await collection.InsertOneAsync(new User { ExternalId = (UserId)guid });
var user = await collection.Find(Builders<User>.Filter.In(x => (Guid)x.ExternalId, new[] { guid }))
.FirstOrDefaultAsync();
// MongoDB.Driver.Linq.ExpressionNotSupportedException : Expression not supported: Convert(x.ExternalId, Guid).
Assert.That(user, Is.Not.Null);
}
private class User
{
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("externalId")]
public UserId ExternalId { get; set; }
}
private readonly struct UserId
{
private readonly Guid _id;
public UserId(Guid id)
{
_id = id;
}
public static explicit operator Guid(UserId source) => source._id;
public static explicit operator UserId(Guid id) => new UserId(id);
}
private class UserIdBsonSerializer : StructSerializerBase<UserId>
{
private readonly GuidSerializer _guidSerializer = new GuidSerializer();
public override UserId Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) =>
new UserId(_guidSerializer.Deserialize(context, args));
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args,
UserId value) =>
_guidSerializer.Serialize(context, args, (Guid)value);
}
}
}