[CSHARP-4819] ReplaceWith not respecting custom element name configured by the serializer Created: 25/Oct/23  Updated: 06/Nov/23

Status: Investigating
Project: C# Driver
Component/s: None
Affects Version/s: 2.22.0
Fix Version/s: None

Type: Bug Priority: Unknown
Reporter: Wassim Khalil Assignee: Robert Stam
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to CSHARP-4555 Linq3 projection stage generated by g... Backlog
is related to CSHARP-4579 Pipeline projection translator does n... Closed

 Description   

Summary

ReplaceWith, ReplaceRoot & Project pipeline stages don't seem to respect the serializer's configuration when using a new expression of a customized class map.

How to Reproduce

Run the following unit test

public class ReplaceWithBug
{
    [Fact]
    public void ReplaceWithShouldRenderElementNameCorrectly()
    {
        BsonClassMap.RegisterClassMap<User>(cm =>
        {
            cm.AutoMap();
            cm.MapMember(c => c.UserId).SetElementName("uuid");
        });
 
        var client = new MongoClient(new MongoClientSettings { LinqProvider = MongoDB.Driver.Linq.LinqProvider.V3 });
        var collection = client.GetDatabase("db").GetCollection<User>("user");
 
        var rendered = PipelineStageDefinitionBuilder
            .ReplaceWith<User, User>(u => new User { UserId = u.UserId })
            .Render(collection.DocumentSerializer, collection.Settings.SerializerRegistry, collection.Database.Client.Settings.LinqProvider);
 
        var bson = rendered.Document.ToString();
 
        Assert.Equal("""{ "$replaceWith" : { "uuid" : "$uuid" } }""", bson);
    }
}
 
public class User
{
    public Guid UserId { get; set; }
}

 

Running the unit test produces the following error:

  Message: 
    Assert.Equal() Failure: Strings differ
                                     ↓ (pos 22)
    Expected: "{ "$replaceWith" : { "uuid" : "$uuid" } }"
    Actual:   ···""$replaceWith" : { "UserId" : "$uuid" } }"
                                      ↑ (pos 22)



 Comments   
Comment by Robert Stam [ 01/Nov/23 ]

I'm sorry the workaround doesn't work for you given your architecture.

We do plan to address this issue but I'm not sure when.

Comment by Wassim Khalil [ 01/Nov/23 ]

Thanks robert@mongodb.com for your detailed response.

Unfortunately, the work around you suggested doesn't work for us, as we follow onion architecture in our codebase and the User class lives in the domain layer (at the center of the onion) with no dependencies on the outside world. It's the persistence layer's responsibility to configure the correct mapping and serialization of the domain layer models to various persistence technologies like MongoDB. In other words, the domain layer doesn't have a direct or indirect dependency on MongoDB driver.

Comment by Robert Stam [ 31/Oct/23 ]

Thank you for reporting this. I am able to reproduce it.

This is going to be non-trivial to fix. 

Currently we create a new class map when translating an `Expression` that calls a constructor. The reason we do that is that we want to make sure that the serializer we create to handle the result correctly deserializes all inputs to the constructor (which might be serialized in custom ways).

I realize that in the case of `ReplaceWith` what we really need is to make sure the result is compatible with the collection's document serializer.

As a partial workaround you could use an attribute instead of the code you have in a constructor:

public class User
{
    [BsonElement("uuid")] public Guid UserId { get; set; }
}

 

 

Comment by PM Bot [ 25/Oct/23 ]

Hi wassimk@vypex.com, thank you for reporting this issue! The team will look into it and get back to you soon.

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