Search code examples
c#mongodbmongodb-.net-driver

"Unable to determine the serialization information for" error on MongoDB complex type equal to null filter


I am getting the below error while trying to run equal filter against null for a complex type object in MongoDB.Driver 2.0:

InvalidOperationException: Unable to determine the serialization information for e => e.Deletion. at MongoDB.Driver.ExpressionFieldDefinition2.Render(IBsonSerializer1 docume ntSerializer, IBsonSerializerRegistry serializerRegistry) at MongoDB.Driver.SimpleFilterDefinition2.Render(IBsonSerializer1 documentS erializer, IBsonSerializerRegistry serializerRegistry) at MongoDB.Driver.AndFilterDefinition1.Render(IBsonSerializer1 documentSeri alizer, IBsonSerializerRegistry serializerRegistry) at MongoDB.Driver.MongoCollectionImpl1.FindOneAndUpdateAsync[TProjection](Fi lterDefinition1 filter, UpdateDefinition1 update, FindOneAndUpdateOptions2 op tions, CancellationToken cancellationToken)

This is the filter:

Builders<TEntity>.Filter.Eq(e => e.Deletion, null)

In order to reproduce, run the following code with MongoDB.Driver 2.0.0 version:

public sealed class OccuranceWithReason
{
    public OccuranceWithReason() : this(null)
    {
    }

    public OccuranceWithReason(string reason)
    {
        Reason = reason;
        OccuredOn = DateTime.UtcNow;
    }

    public string Reason { get; private set; }
    public DateTime OccuredOn { get; private set; }
}

public interface IDeletable
{
    OccuranceWithReason Deletion { get; }
}

public abstract class BaseEntity : IDeletable
{
    protected BaseEntity()
    {
        Id = ObjectId.GenerateNewId().ToString();
    }

    public string Id { get; private set; }
    public int PeekedCount { get; set; }
    public OccuranceWithReason Deletion { get; private set; }
}

public class FooEntity : BaseEntity
{
}

class Program
{
    static void Main(string[] args)
    {
        MongoConfig.Configure();
        var client = new MongoClient();
        var db = client.GetDatabase("foo");
        var fooCol = db.GetCollection<FooEntity>("foos");
        var foo = PeekForInsertSync(fooCol);
    }

    public static TEntity PeekForInsertSync<TEntity>(IMongoCollection<TEntity> collection)
        where TEntity : BaseEntity
    {
        var query = Builders<TEntity>.Filter.And(
            Builders<TEntity>.Filter.Eq(e => e.Deletion, null),
            Builders<TEntity>.Filter.Lte(e => e.PeekedCount, 10)
        );

        return collection.Find(query).FirstOrDefaultAsync().Result;
    }

}

internal static class MongoConfig
{
    public static void Configure()
    {
        RegisterConventions();
        RegisterGlobalSerializationRules();
        ConfigureEntities();
        ConfigureValueObjects();
    }

    private static void RegisterConventions()
    {
        var pack = new ConventionPack { new CamelCaseElementNameConvention(), new IgnoreIfNullConvention(false) };
        ConventionRegistry.Register("all", pack, t => true);
    }

    private static void RegisterGlobalSerializationRules()
    {
        BsonSerializer.UseNullIdChecker = true;
    }

    private static void ConfigureEntities()
    {
        BsonClassMap.RegisterClassMap<BaseEntity>(cm =>
        {
            cm.MapMember(c => c.Id).SetSerializer(new StringSerializer(BsonType.ObjectId));
            cm.SetIdMember(cm.GetMemberMap(c => c.Id));
        });
    }

    private static void ConfigureValueObjects()
    {
        BsonClassMap.RegisterClassMap<OccuranceWithReason>(cm =>
        {
            cm.AutoMap();
            cm.MapCreator(occurance => new OccuranceWithReason(occurance.Reason));
        });
    }
}

Any idea?


Solution

  • The problem is about the BaseEntity object serialization registration. Deletion property was not mapped. Auto mapping all fields solved the problem:

    BsonClassMap.RegisterClassMap<BaseEntity>(cm =>
    {
        cm.AutoMap();
        cm.MapMember(c => c.Id).SetSerializer(new StringSerializer(BsonType.ObjectId));
        cm.SetIdMember(cm.GetMemberMap(c => c.Id));
    });