将数组插入 MongoDB 中的子集合会忽略 _t 鉴别器

Inserting an array into a child collection in MongoDB is omitting the _t Discriminator

鉴于这些 类:

public class Parent
{
    public IEnumerable<IChild> Children { get; set; }
}

public interface IChild { }

public class Child : IChild { }

像这样将子项 属性 作为数组插入:

using MongoDB.Driver;
using System.Collections.Generic;

namespace TestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var db = new MongoClient().GetDatabase("Test");
            var collection = db.GetCollection<Parent>("Parent");
            collection.InsertOne(new Parent { Children = new[] { new Child() } });
        }
    }
}

数据库中缺少 _t 鉴别器:

{
    "_id":"5bf6aef6c0beccc414b70d45",
    "Child":[{}]
}

如果我改用列表:

collection.InsertOne(new Parent { Children = new List<IChild> { new Child() } });

_t 鉴别器设置正确:

{
    "_id":"5bf6b074c0beccc414b70dc2",
    "Children":[{"_t":"Child"}]
}

这似乎是一个错误,或者至少是一个非常不直观的行为。

附加信息: 该行为是一个问题,因为缺少的 _t 鉴别器在反序列化对象时导致异常:

System.FormatException: 'An error occurred while deserializing the Children property of class TestConsoleApp.Parent: Unable to determine actual type of object to deserialize for interface type TestConsoleApp.IChild.'

在我看来,这就是你所说的一个错误,实际上考虑到你提到的异常可能是一个错误。 无论如何,这是项目 https://github.com/mongodb/mongo-csharp-driver 的 GitHub 存储库。

在 README.md 中,您可以找到有关如何报告错误的说明(如果您不打算报告,请告诉我,我会这样做)。

与此同时,我认为最好的解决方案是将 IEnumerable<IChild> 替换为 IList<IChild>,以防止其他程序员以错误的方式插入数据。

编辑:请检查 IList 是否解决了问题,因为该行正在编译(至少对我而言)

    public static IList<int> Ints { get; set; }

    static void Main(string[] args)
    {
        Ints = new[] {1,2,3,4};
        Console.WriteLine("Hello World!");
    }

如果它不能解决您的问题,我会直接使用 List<IChild>。它不漂亮,但它会起作用。

问题是因为 mongo 发现的 IChild 接口没有实现 class。换句话说,mongo driver 不知道必须使用 Child class 创建 IChild 实现。这就是它添加 _t 鉴别器的原因。

要解决此问题,您可以指定隐式序列化。

public class Parent
{
[BsonSerializer(typeof(ImpliedImplementationInterfaceSerializer<IEnumerable<IChild>, IEnumerable<Child>>))]
    public IEnumerable<IChild> Children { get; set; }
}

使用此属性,它不会创建 _t 歧视,但会使用 Child class 进行反序列化。

如果你想在动态实例上强制使用鉴别器,你可以使用

[BsonDiscriminator(Required = true)]
    public class Child : IChild { }

请注意,应将此 header 添加到您需要强制创建鉴别器的所有 classes。