6

MongoDB.Drivers在我的 C# MVC 应用程序中使用与 Mongodb 数据库进行通信。

C# 代码

            var client = new MongoClient("mongodb://localhost:27012");
            var db = client.GetDatabase("Test_DB");
            var collection = db.GetCollection<BsonDocument>("TestTable");
            var tData = await collection.FindAsync(new BsonDocument(true)); // I used - new BsonDocument(true)  to specify allow duplicate element name while read data.

MongoDB数据图片 在此处输入图像描述

在上图中,您可以看到我有多个DuplicateCol使用不同值调用的列。当我尝试在c#using中读取这些数据时,MongoDB.Driver出现以下错误:InvalidOperationException: Duplicate element name 'DuplicateCol'.

在插入重复的元素名称时,我使用AllowDuplicateNames=trueBsonDocument对象如下。(它插入重复的元素名称而不会出错。)

BsonDocument obj = new BsonDocument();
obj.AllowDuplicateNames = true;
obj.Add("DuplicateCol", "Value_One");
obj.Add("propone", "newVal");
obj.Add("DuplicateCol", "Value_Two");
.... // other properties with value 
await collection.InsertOneAsync(obj);

注意:此架构是必须的。我不能改变它。

请向我提供解决此问题的建议。任何帮助将不胜感激..

谢谢。

4

2 回答 2

9

如果没有其他帮助,您查看了其他答案和评论,并且仍然认为您绝对必须在问题中描述设计,您可以使用以下技巧。像这样创建类:

class AlwaysAllowDuplicateNamesBsonDocumentSerializer : BsonDocumentSerializer {
    protected override BsonDocument DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) {
        if (!context.AllowDuplicateElementNames)
            context = context.With(c => c.AllowDuplicateElementNames = true);
        return base.DeserializeValue(context, args);
    }

    public override BsonDocument Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) {
        if (!context.AllowDuplicateElementNames)
            context = context.With(c => c.AllowDuplicateElementNames = true);
        return base.Deserialize(context, args);
    }
}

这是自定义序列化程序,在反序列化时BsonDocument始终设置AllowDuplicateElementNames。然后你需要一些反思来覆盖默认的BsonDocument序列化程序(因为BsonDocumentSerializer.Instance没有设置器):

// get __instance field, which is backing field for Instance property
var instanceField = typeof(BsonDocumentSerializer).GetField("__instance", BindingFlags.Static | BindingFlags.NonPublic);
// overwrite with our custom serializer
instanceField.SetValue(null, new AlwaysAllowDuplicateNamesBsonDocumentSerializer());

通过在启动时的某个地方执行此操作,您将能够读取具有重复属性的文档。

完整的测试代码:

static void Main(string[] args) {
    var instanceField = typeof(BsonDocumentSerializer).GetField("__instance", BindingFlags.Static | BindingFlags.NonPublic);
    instanceField.SetValue(null, new AlwaysAllowDuplicateNamesBsonDocumentSerializer());
    TestMongoQuery();
    Console.ReadKey();
}

static async void TestMongoQuery() {
    var client = new MongoClient();
    var db = client.GetDatabase("Test_DB");            
    var collection = db.GetCollection<BsonDocument>("TestTable");
    using (var allDocs = await collection.FindAsync(FilterDefinition<BsonDocument>.Empty)) {
        while (allDocs.MoveNext()) {
            foreach (var doc in allDocs.Current) {
                var duplicateElements = doc.Elements.Where(c => c.Name == "DuplicateCol");
                foreach (var el in duplicateElements) {
                    Console.WriteLine(el.Name + ":" + el.Value);
                }
            }
        }
    }
}
于 2018-02-07T12:35:02.680 回答
4

您收到的错误是设计使然

InvalidOperationException: Duplicate element name 'DuplicateCol'

正如 CodeFuller 所说,MongoDB 文档键应该是唯一的。如果您需要一个包含重复字段名称的文档并且您无法更改此架构,那么 MongoDB 可能不是适合您的数据库解决方案……我不知道哪一个会说实话。尽管似乎可以使用以下方法保存重复的密钥:

AllowDuplicateNames=true

我想您将在查询和索引等方面遇到挑战。

可以说这种模式是一个非常奇怪的要求。更合适的架构可能是:

{
    "_id" : ObjectId("xxx"),
    "propTest" : 0,
    ...
    "duplicateCol": [ "Value_Two", "Value_One" ]
}

在这里,您有一个属性 (duplicateCol),它是一个接受多个字符串的数组。

于 2018-02-06T11:28:13.850 回答