[CSHARP-4580] ExtraElements containing POCO classes fail to serialize Created: 24/Mar/23  Updated: 10/Apr/23

Status: Backlog
Project: C# Driver
Component/s: Serialization
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Minor - P4
Reporter: Ahmed Fwela Assignee: Boris Dogadov
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Summary

When serializing a POCO class in ExtraElements, I get 
__

.NET type xxxx cannot be mapped to a BsonValue.

Driver version: 2.19

How to Reproduce

The problem is in the code here

Github Link

It's using

BsonTypeMapper.MapToBsonValue

 on all fields, which will fail for class maps

Additional Background

The POCO classes are owned by another library, and I have no access to them, so the only way I can customize their behavior is by manipulating ExtraElements



 Comments   
Comment by Boris Dogadov [ 10/Apr/23 ]

Hi ahmednfwela@bdaya-dev.com 
To summarize, ExtraElements's original intention is to provide a mechanism not to lose extra data when reading and writing back to database. As of now, there is no support for writing POCOs via ExtraElements mechanism.

We will evaluate supporting POCOs in ExtraElements feature as part of our roadmap.

Comment by Boris Dogadov [ 27/Mar/23 ]

Thanks ahmednfwela@bdaya-dev.com,

We will investigate this use case further.

Comment by Ahmed Fwela [ 27/Mar/23 ]

Exact use case: ABP framework

they support extending objects by an arbitrary 

Dictionary<string, object?>

instead of users redefining their classes, but currently they are mapping those extra fields as extra elements so that they would go into the original object (and feel kind of natural in the database)

 

Comment by Boris Dogadov [ 27/Mar/23 ]

Hi ahmednfwela@bdaya-dev.com 

Currently POCOs are not supported in ExtraElements. The proposed workaround does solve the serialization issue, but unfortunately does not support a serialization/deserialization roundtrip (POCOs are deserialized as Dictionary).
The original intention of ExtraElements was not to lose the extra data that is read and written back to DB. As opposed to the case when the data model is known when writing.

Depending on the particular use case, there might be different more suitable solutions for this problem. For example just having non ExtraElements member:

public IDictionary<string, object> MyObjects;

It would be helpful to understand the exact use case better, in order to recommend the best solution.

Comment by Ahmed Fwela [ 24/Mar/23 ]

workaround:

public class BsonValueClassMapper<T> : ICustomBsonTypeMapper
{
    public bool TryMapToBsonValue(object value, out BsonValue bsonValue)
    {
        if (value is not T casted)
        {
            bsonValue = BsonNull.Value;
            return false;
        }
        bsonValue = casted.ToBsonDocument();
        return true;
    }
}

for each class:

BsonTypeMapper.RegisterCustomTypeMapper(typeof(Class1), new BsonValueClassMapper<Class1>());
BsonTypeMapper.RegisterCustomTypeMapper(typeof(Class2), new BsonValueClassMapper<Class2>());

 

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