I have a collection in my database where I log events. Each type of event has a different set of data. I've defined this with the following class:
[CollectionName("LogEvent")]
public class LogEvent
{
public LogEvent(string eventType)
{
EventType = eventType;
EventData = new Dictionary<string, object>();
}
public string EventType { get; private set; }
[BsonExtraElements]
public IDictionary<string, object> EventData { get; private set; }
}
Now - this works pretty good to some extent. As long as the elements of the EventData
dictionary are simple types...
var event = new LogEvent("JobQueues"){
EventData = new Dictionary<string, object>(){
{ "JobId": "job-123" },
{ "QueueName": "FastLane" }
}
}
_mongoCollection.InsertOne(event);
...I get mongo documents like
{
_id: ObjectId(...),
EventType: "JobQueued",
JobId: "job-123",
QueueName: "FastLane"
}
But as soon as I try to add a custom type to the dictionary, things stops working.
var event = new LogEvent("JobQueues"){
EventData = new Dictionary<string, object>(){
{ "JobId": "job-123" },
{ "QueueName": "FastLane" },
{ "JobParams" : new[]{"param-1", "param-2"}},
{ "User" : new User(){ Name = "username", Age = 10} }
}
}
This gives me errors like ".NET type ... cannot be mapped to BsonType."
If I remove the [BsonExtraElements]
tag, and [BsonDictionaryOptions(DictionaryRepresentation.Document)]
It will start serialize stuff without errors, but it will give me a complete different document which I don't like..
{
_id: ObjectId(...),
EventType: "JobQueued",
EventData: {
JobId: "job-123",
QueueName: "FastLane",
User: {
_t: "User",
Name: "username",
Age: 10
},
JobParams : {
_t: "System.String[]",
_v: ["param-1", "param-2"]
}
}
}
What I want, is the following result:
{
_id: ObjectId(...),
EventType: "JobQueued",
JobId: "job-123",
QueueName: "FastLane",
User: {
Name: "username",
Age: 10
},
JobParams : ["param-1", "param-2"]
}
Does anyone know how to achieve that?
(I'm using the C# mongodriver v2.3)
So works MongoDriver, because it needs information of the type to deserilize it back. What you could do, is to write and register your own CustomMapper for User class:
public class CustomUserMapper : ICustomBsonTypeMapper
{
public bool TryMapToBsonValue(object value, out BsonValue bsonValue)
{
bsonValue = ((User)value).ToBsonDocument();
return true;
}
}
Somewhere on starting program:
BsonTypeMapper.RegisterCustomTypeMapper(typeof(User), new CustomUserMapper());
That will work, and i have managed to serialize your data exact as you want.
But: As you want to deserialize it back, you wil get your User
class as Dictionary
, because driver will have no information about hiow to deserialize it:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With