繁体   English   中英

Mongo C# 驱动程序:反序列化 BsonValue

[英]Mongo C# Driver: Deserialize BsonValue

我在 mongodb 中有一个文件,其结构类似于:

{
  "_id": "abcdef01234",
  "Name": "Product A",
  "Dimensions": [
    {
      "Height": 32,
      "Width": 64
    },
    {
      "Height": 16,
      "Width": 32
    },
    {
      "Height": 8,
      "Width": 16
    }
  ]
}

我还定义了一个 class 来表示尺寸(上面的子文档)

public class Dimension
{
  public int Height { get; set; }
  public int Width { get; set; }
}

我以这种方式选择“产品 A”文档:

MongoServer srv = MongoServer.Create(myConnStr);
BsonDocument doc = srv["db"]["products"].FindOneById(ObjectId.Parse("abcdef01234"));
BsonValue dimensionsVal = doc["Dimensions"];

现在我有一个名为 dimensionsVal 的 BsonValue,它的类型是 BsonArray。 我真正想要的是一个 List<Dimension>。 如何将 dimensionsVal 转换为 List<Dimension>?

编辑尺寸 class 实际上比我描述的要复杂得多。 由于 memory 问题,我想将尺寸与产品分开。 我想将产品保留在 memory 中,而不是(可能巨大的)尺寸列表。 因此,我不想将列表作为产品 class 的属性。

这是如何完成的:

using MongoDB.Bson.Serialization;

MongoServer srv = MongoServer.Create(myConnStr);
BsonDocument doc = srv["db"]["products"].FindOneById(ObjectId.Parse("abcdef01234"));
BsonValue dimVal = doc["Dimensions"];
List<Dimension> d = BsonSerializer.Deserialize<List<Dimension>>(dimVal.ToJson());

尝试这个:

public class Product
{
   [BsonId]
   public ObjectId Id { get; set; }

   public string Name{ get; set; }

   public List<DimensionDoc> Dimensions{ get; set; }
}

public class DimensionDoc
{
   public int Height { get; set; }
   public int Width { get; set; }

}

Product product = srv["db"]["products"].FindOneByIdAs<Product>(ObjectId.Parse("abcdef01234"));

product.Dimensions 现在将包含您需要的 List<>。

更新:

您可能正在寻找包含/排除功能。 在 c# 驱动程序中这样做:

 // load products without array of Dimensions
MongoCursorInstance.SetFields(Fields.Exclude("Dimensions"));
//load empty product with Dimensions and _id
MongoCursorInstance.SetFields(Fields.Include("Dimensions"));

为什么不为产品创建 class? 在这种情况下,驱动程序将能够自动反序列化数据:

class Product
{
   [BsonId]
   public ObjectId Id { get; set; }

   public string Name{ get; set; }

   public List<Dimension> Dimensions{ get; set; }

}

var product = srv["db"]["products"].FindOneByIdAs<Product>();
var dimentions = product.Dimensions;

但是如果你不想创建Product class 你可以 go 这种方式:

BsonArray dimensionsVal = doc["Dimensions"].AsBsonArray;

var list = new List<Dimension>();
foreach (BsonValue value in dimensionsVal)
{
  var bsonDoc = (BsonDocument) value;
  var d = new Dimension();
  d.Height = bsonDoc["Height"];
  d.Width = bsonDoc["Width"];
  list.Add(d);
}

正如其他人所建议的那样,我将声明您的 class 具有 List<Dimension> 类型的 Dimensions 属性。 然后,如果您想读取没有维度值的产品,请写下:

ObjectId productId;
var query = Query.EQ("_id", productId);
var fields = Fields.Exclude("Dimensions");
var product = collection.Find(query).SetFields(fields).FirstOrDefault();
// product.Dimensions will be null because there was no data for it

当您想阅读包括所有尺寸在内的完整产品时,请写下:

ObjectId productId;
var query = Query.EQ("_id", productId);
var product = collection.FindOne(query);
// product.Dimensions will be populated this time

这比将维度读入 BsonDocument 并使用手写代码将它们转换为 List<Dimension> 效率更高。 这种方法会导致在 memory 中加载数据的两个副本(尽管如果您不保留对 BsonDocument 版本的引用,那么之后可能很快就会对 BsonDocument 版本进行垃圾收集)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM