将数组插入MongoDB的子集合中会省略_t Discriminator

时间:2018-11-22 13:45:14

标签: c# .net mongodb mongodb-.net-driver

给出以下类别:

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

public interface IChild { }

public class Child : IChild { }

将Children属性插入为这样的数组:

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:'反序列化类TestConsoleApp.Parent的Children属性时发生错误:无法为接口类型TestConsoleApp.IChild确定要反序列化的对象的实际类型。'

2 个答案:

答案 0 :(得分:2)

引起此问题的原因是mongo没有发现IChild接口的实现类。换句话说,mongo驱动程序不知道必须使用Child类创建IChild实现。这就是为什么要添加_t Discriminator。

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

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

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

如果要在动态实例上强制使用鉴别符,则可以使用

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

请注意,应将此标头添加到所有需要强制创建标识符的类中。

答案 1 :(得分:1)

我认为,这是您所说的错误,实际上是考虑到您提到的异常可能是一个错误。 无论如何,这是项目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>。虽然不漂亮,但是可以使用。