C# MongoDb 序列化 Dictionary<string, object>

5

我在数据库中有一个收集事件的集合。每种类型的事件都有不同的数据集。我已经使用以下类定义了这个集合:

[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; }
}

现在——这个方法在某种程度上已经相当不错了。只要 EventData 字典的元素是简单类型...

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"
}

但是一旦我尝试向字典添加自定义类型,事情就停止工作了。
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} }
    }
}

这会给我带来错误,例如".NET类型...无法映射到BsonType。"

如果我删除[BsonExtraElements]标记和[BsonDictionaryOptions(DictionaryRepresentation.Document)],它将开始序列化内容而不出现错误,但它将给我一个完全不同的文档,这是我不喜欢的。

{
  _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"]
}

有人知道如何实现吗?

(我正在使用C# mongodriver v2.3)

1个回答

3

所以MongoDriver工作的原因是它需要该类型的信息才能将其反序列化回来。 你可以编写并注册自己的User类CustomMapper:

public class CustomUserMapper : ICustomBsonTypeMapper
{
    public bool TryMapToBsonValue(object value, out BsonValue bsonValue)
    {
        bsonValue = ((User)value).ToBsonDocument();
        return true;
    }
}

程序启动时的某个位置:

BsonTypeMapper.RegisterCustomTypeMapper(typeof(User), new CustomUserMapper());

这样做是可行的,我已经成功地将您的数据序列化成了您想要的格式。

但是:如果您想要将其反序列化回来,您将会得到一个Dictionary类型的User类对象,因为驱动程序不知道如何反序列化它:

enter image description here


反序列化不是问题。这是一个“仅追加”集合,在极少数情况下,如果需要读取回来的话,将通过自定义投影来实现。 无论如何,自定义序列化器并不是一个好选择,因为其中一个目的是能够向日志中添加“任何内容”。 - Vegar
我已经想到了一种解决方法,首先使用json.net将数据序列化为json格式,然后请求mongo将json转换为bsondocument。虽然这种方法有点可行,但并不是最优解决方案... - Vegar
@Vegar 也许你的解决方法是最好的方案。MongoDrive 可以添加任何东西到集合中,但它想要确保能够精确地以相同的形式取回它,为此它使用类型描述符。 - Maksim Simkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接