[CSHARP-4579] Pipeline projection translator does not use registered BsonClassMap and throws exception Created: 23/Mar/23 Updated: 31/Oct/23 Resolved: 25/Mar/23 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | Linq, LINQ3 |
| Affects Version/s: | None |
| Fix Version/s: | None |
| Type: | Bug | Priority: | Unknown |
| Reporter: | x y | Assignee: | Oleksandr Poliakov |
| Resolution: | Works as Designed | Votes: | 0 |
| Labels: | .net, c# | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Issue Links: |
|
||||||||
| Documentation Changes Summary: | 1. What would you like to communicate to the user about this feature? |
||||||||
| Description |
| Comments |
| Comment by Robert Stam [ 27/Mar/23 ] | |||||||||||||||||
|
Interesting... I can't tell for sure whether you are only updating existing documents or adding new ones (depends on whether your are altering the UniqueId value or not in "other values"). If you are only updating existing documents you might want to consider using the overload of UpdateMany that applies a pipeline to each document that is to be updated. I believe that would be more efficient than using $merge back into the same collection. We will consider whether it would be possible to use an existing registered class map (instead of automapping a new one) for you projection scenario. We would still have to overwrite the registered class map's serializers with serializers determined by the values flowing into the projection from the previous stage (working on a clone of the registered class map because the registered one is read-only). Most of the time the serializers flowing out from the previous stage would be equivalent to the serializers configured in the registered class map, but in case they don't match we have to use the serializer that matches the actual data coming from the previous stage. As long as all the serializers for each property in the pipeline projection match the serializers for the same properties in the registered class map you could then in principle $merge the documents back to the same collection. If they didn't match the new inserted or updated documents might have data serialized in a different representation. | |||||||||||||||||
| Comment by x y [ 27/Mar/23 ] | |||||||||||||||||
|
My original code was about cloning some of the documents to the same collection with altering some of the properties. I wanted to solve this by adding a merge to the end of the pipeline. In this example, I need the projection to keep the same property names from the original object, and any other settings from the registered BsonClassMap to match the schema of the collection.
| |||||||||||||||||
| Comment by Robert Stam [ 27/Mar/23 ] | |||||||||||||||||
|
The reason we don't rely on any class maps that might have been registered is that there is no guarantee that the incoming data from the previous stage is serialized the same way as the members of the registered class map. They probably are, but there is no guarantee. So we build a new class map whose member serializers are derived from the data flowing into the projection. I'm not sure I understand why the element names matter. As long as the driver correctly deserializes the results returned from the server the element names could be anything. | |||||||||||||||||
| Comment by x y [ 25/Mar/23 ] | |||||||||||||||||
|
OK, this workaround could work for the Id property, but what about the second code example I provided? It's not just the Id property, it's about using the full dynamic power of BsonClassMap.
If I have a scenario, where property names are not known in advance when writing the code, only at runtime, how can I have the projection give correct results? For example, when the program starts, it reads the mapping information from some data store, and registers BsonClassMaps based on that. In this case I cannot add a BsonElement attribute in advance to the properties, and if I register a BsonClassMap, that wouldn't work for projection. Is there a way to make the projection work correctly in this scenario?
| |||||||||||||||||
| Comment by Robert Stam [ 25/Mar/23 ] | |||||||||||||||||
|
While it is true that the LINQ3 translator does not use any registered class maps, it does use the class map automapping feature, which means that it will see and respect any attributes on the class declaration. But you need to use a slightly different technique to suppress the automatic mapping of the `Id` property to the `_id` element name:
The trick is to use the `[BsonNoId]` attribute on the class, rather than `[BsonElement("Id")]` on the property itself. You can see my repro (including a new scenario that also projects the `UniqueId` also) here: https://github.com/rstam/mongo-csharp-driver/tree/csharp4579 |