Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support defining the serializer and BSON representation for a property #358

Open
CristianBonilla opened this issue Jun 3, 2023 · 15 comments
Labels
affects-serialization Serialization-related issue enhancement Enhancements & features moderate-change Moderate changes required

Comments

@CristianBonilla
Copy link

CristianBonilla commented Jun 3, 2023

Issue converted to Proposal by @Turnerj 2023-06-04

Proposal

Allow finer control of the serialization system for MongoDB through MongoFramework. Currently you can not control the BSON Representation (eg. C# string can't be represented as BSON ObjectId) however doing so allows greater compatibility in a number of scenarios.

This could be accomplished well with support for defining the serializer per-property in MongoFramework. With the appropriate extension methods during the builder process, you could then control the representation that would be used. This first-party support would then unlock the ability to do the same attribute-level control of serializer (and optionally representation).

Original Issue

It does not allow me to read the entities of a mongo database due to this problem.

image image
@CristianBonilla CristianBonilla changed the title An error occurred while deserializing the Id property of class Policies.Customer: Cannot deserialize a 'String' from BsonType 'ObjectId' An error occurred while deserializing the Id property of class: Cannot deserialize a 'String' from BsonType 'ObjectId' Jun 3, 2023
@Turnerj
Copy link
Member

Turnerj commented Jun 3, 2023

It sounds like the existing data in the database isn't actually a string but a ObjectId. Try switching your entities type to ObjectId (its in the MongoDB.Bson namespace).

@CristianBonilla
Copy link
Author

It sounds like the existing data in the database isn't actually a string but a ObjectId. Try switching your entities type to ObjectId (its in the MongoDB.Bson namespace).

@Turnerj it doesn't work like that either

image

@Turnerj
Copy link
Member

Turnerj commented Jun 3, 2023

Sorry, I mean change public string Id { get; set; } to public ObjectId Id { get; set; }

@CristianBonilla
Copy link
Author

Turned out! but to deserialize to string no?

@Turnerj
Copy link
Member

Turnerj commented Jun 3, 2023

It is a little more complicated than that unfortunately. So when you use MongoFramework (or MongoDB's driver directly), if you use a string ID the actual data in MongoDB is literally a string property. ObjectId in MongoDB is actually a binary type.

So what we see happening here is that the DB has a binary ObjectId and C# was told to have a string, that was why it wasn't working.

This gets more unclear because, as far as I know, the name of the ID format that MongoDB uses is called "ObjectId".

It is probably possible to write some sort of converter system to allow string properties in the DB convert to ObjectId (and vice versa, like in your situation) however MongoFramework doesn't support this nor does the MongoDB Driver have anything built-in to do that.

@Turnerj
Copy link
Member

Turnerj commented Jun 3, 2023

Or maybe better explained another way, there are 3 types of IDs for the MongoDB Driver:

  • string
  • ObjectId
  • Guid

Both string and Guid serialize to strings but ObjectId is serialized to a binary format. Your existing data in the DB is using the binary format method (it is ObjectId in the DB) which is why using string in C# didn't work.

@CristianBonilla
Copy link
Author

I did a test using MongoDB.Driver and deserialization works effectively in string, so I don't know if the problem is directly in MongoFramework that does not allow deserialization

image

Result:

image

@Turnerj
Copy link
Member

Turnerj commented Jun 3, 2023

With your example now, you're telling the driver to specifically ignore the default representation for the serializer. There isn't an equivalent way to do so with MongoFramework currently. I've had a look into a few ways I could try and support BSON representation conversion but I'm not really a fan of what I've come up with currently.

I'd probably recommend using the appropriate C# type that matches the data in the database.

@CristianBonilla
Copy link
Author

With your example now, you're telling the driver to specifically ignore the default representation for the serializer. There isn't an equivalent way to do so with MongoFramework currently. I've had a look into a few ways I could try and support BSON representation conversion but I'm not really a fan of what I've come up with currently.

I'd probably recommend using the appropriate C# type that matches the data in the database.

@Turnerj Do you think that in a future version of MongoFramework it will allow serialization like MongoDB.Driver allows?

@Turnerj
Copy link
Member

Turnerj commented Jun 4, 2023

Yes, mostly. Like I think being able to define what a particular property should be represented as is quite useful but I need to look at the bigger picture of how I'd integrate it with MongoFramework.

Right now the very high level design I'm thinking is with MongoFramework's internal mapping system, track the serializer used for a particular property - basically allow you to set IBsonSerializer. From there, I could just add some extension methods to my builder system to allow reconfiguring an existing serializer to change representation.

The big bit with this piece of work is that it makes MongoFramework responsible about what serializer is used for what property. By that I mean, MongoFramework will be determining the default serializer for each type rather than the driver by default. This is probably a good thing to do long term anyway (gives more flexibility in mapping) but given the wide variety of types that people could use, it becomes complicated ensuring backwards compatibility.

The end result then for consumers of MongoFramework would be both a similar attribute like the driver has to define the representation and also have first-party support in the fluent builder system.

@Turnerj Turnerj changed the title An error occurred while deserializing the Id property of class: Cannot deserialize a 'String' from BsonType 'ObjectId' Support defining the serializer and BSON representation for a property Jun 4, 2023
@Turnerj Turnerj added enhancement Enhancements & features affects-serialization Serialization-related issue moderate-change Moderate changes required and removed question labels Jun 4, 2023
@CristianBonilla
Copy link
Author

@Turnerj Is it possible to also allow the camelcase convention, if the properties are in pascal case in an entity?

@Turnerj
Copy link
Member

Turnerj commented Jun 4, 2023

Yep! You can do it via attributes or the mapping builder, have a look at this part of the readme: https://github.com/TurnerSoftware/MongoFramework#entity-mapping-basics

@CristianBonilla
Copy link
Author

Yes, but isn't there a way to make it global by default?

@Turnerj
Copy link
Member

Turnerj commented Jun 4, 2023

No, there isn't a way to have a global default for this. It is something that could be achieved with changes to the PropertyMappingProcessor to take in some configuration but it currently doesn't support it.

@CristianBonilla
Copy link
Author

It would be nice to support it in a future version or find a way to support it in older versions too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
affects-serialization Serialization-related issue enhancement Enhancements & features moderate-change Moderate changes required
Projects
None yet
Development

No branches or pull requests

2 participants