在.NET 4中是否有mongodb C#驱动程序支持System.Dynamic.DynamicObject



我正在处理一个使用 .NET Razor 和 mongodb 的项目。我想做这样的事情:

@{
    var feeds = DP.Database.GetCollection("feeds").FindAll();
}
<ul>
    @foreach (dynamic feed in feeds)
    {
        <li>@feed.message - @feed.from.name</li>
    }
</ul>

但是,当前的mongodb C#驱动程序FindAll()返回不支持动态对象的BsonDocument集合。有人知道.NET 4动态支持的mongodb C#驱动程序吗?

多谢

我创建了一个对MongoDB驱动程序的直接扩展,该扩展使用 Json.NET 重新序列化BSON文档并将其反序列化为动态文档。通过包含以下类,您可以简单地将MongoDB查询转换为动态查询,如下所示

dynamic obj = collection.FindOneByIdAs<BsonDocument>(someObjectId).ToDynamic();

扩展类:

public static class MongoDynamic
{
    private static System.Text.RegularExpressions.Regex objectIdReplace = new System.Text.RegularExpressions.Regex(@"ObjectId((.[a-f0-9]{24}.))", System.Text.RegularExpressions.RegexOptions.Compiled);
    /// <summary>
    /// deserializes this bson doc to a .net dynamic object
    /// </summary>
    /// <param name="bson">bson doc to convert to dynamic</param>
    public static dynamic ToDynamic(this BsonDocument bson)
    {
        var json = objectIdReplace.Replace(bson.ToJson(), (s) => s.Groups[1].Value);
        return Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(json);
    }
}

请务必引用Newtonsoft.Json.dll(http://james.newtonking.com/projects/json-net.aspx)

目前,MongoDB驱动程序中不支持动态。 这是因为它基于 .NET 3.5。 但是,由于 .NET 4.0 程序集可以引用 .NET 3.5 程序集,因此可以在 .NET 4.0 中编写 IBsonSerializationProvider 和 IBsonSerializer 来支持动态。

我们,10gen,正在考虑在未来这样做。 如果你想看一看,我已经在 https://github.com/craiggwilson/mongo-csharp-driver/tree/dynamic 上获得了一些支持。 肯定有错误,但它表明这是可能的。

我有一个使用自定义IBsonSerializer和Newtonsoft.Json的干净解决方案。

在 BsonClassMap 上设置自定义序列化程序

map.MapProperty(member => member.Data)
   .SetElementName("Data")
   .SetSerializer(new DynamicSerializer());

或在物业上

[BsonSerializer(typeof(DynamicSerializer))]
public dynamic Data { get; set; }

并且只包括以下类

public class DynamicSerializer : IBsonSerializer
{
  #region Implementation of IBsonSerializer
  public object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
  {
    return Deserialize(bsonReader, nominalType, null, options);
  }
  public object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType,
    IBsonSerializationOptions options)
  {
    if (bsonReader.GetCurrentBsonType() != BsonType.Document) throw new Exception("Not document");
    var bsonDocument = BsonSerializer.Deserialize(bsonReader, typeof(BsonDocument), options) as BsonDocument;
    return JsonConvert.DeserializeObject<dynamic>(bsonDocument.ToJson());
  }
  public IBsonSerializationOptions GetDefaultSerializationOptions()
  {
    return new DocumentSerializationOptions();
  }
  public void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
  {
    var json = (value == null) ? "{}": JsonConvert.SerializeObject(value);
    BsonDocument document = BsonDocument.Parse(json);
    BsonSerializer.Serialize(bsonWriter, typeof(BsonDocument), document,options); 
  }
  #endregion
}

信息单 - 全球动力

只是为了建立在马克西米利安的答案之上。这将返回来自任何查询的动态列表。

    /// <summary>
    /// deserializes this BsonDocument cursor result to a list of .net dynamic objects
    /// </summary>
    /// <param name="cursor">cursor result to convert to dynamic</param>
    /// <returns></returns>
    public static List<dynamic> ToDynamicList(this MongoCursor<BsonDocument> cursor)
    {
        var dynamicList = new List<dynamic>();
        var list = cursor.ToList();
        for (int i = 0, l = list.Count; i < l; i++)
            dynamicList.Add(list[i].ToDynamic());
        return dynamicList;
    }

尽管这是一个古老的话题,但它今天仍然与发布帖子时一样重要,而且我还没有看到任何为双向支持提供简单解决方案的解决方案,我已经修改了 Scherer 代码@Maximilian以便它允许您转换为动态对象,让您轻松再次保存文档。

public static class MongoDynamic
{
    /// <summary>
    /// deserializes this bson doc to a .net dynamic object
    /// </summary>
    /// <param name="bson">bson doc to convert to dynamic</param>
    public static dynamic ToDynamic(this BsonDocument bson)
    {
        var json = bson.ToJson(new MongoDB.Bson.IO.JsonWriterSettings { OutputMode = JsonOutputMode.Strict });
        dynamic e =  Newtonsoft.Json.JsonConvert.DeserializeObject<ExpandoObject>(json);
        BsonValue id;
        if (bson.TryGetValue("_id", out id))
        {
            // Lets set _id again so that its possible to save document.
            e._id = new ObjectId(id.ToString());
        }
        return e;
    }
}

用法示例:

// Get BsonDocument from db here
BsonDocument doc = ...
// Convert to dynamic.
var d = doc.ToDynamic();
// Lets add a none existant property.
d.Name = "test";
// Assuming you already have your collection set up
collection.Save(new BsonDocument(d));

最新更新