При вставке массива в дочернюю коллекцию в MongoDB пропускается дискриминатор _t - PullRequest
0 голосов
/ 22 ноября 2018

С учетом этих классов:

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: 'Произошла ошибка при десериализации свойства Childrenкласса TestConsoleApp.Parent: невозможно определить фактический тип объекта для десериализации для типа интерфейса TestConsoleApp.IChild. '

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Проблема вызвана тем, что mongo не обнаружил класс реализации интерфейса IChild.Другими словами, драйвер mongo не знает, что реализация IChild должна быть создана с использованием класса Child.Вот почему он добавляет _t Discriminator.

Чтобы решить эту проблему, вы можете указать подразумеваемую сериализацию.

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

С этим атрибутом он не будет создавать _t Discrimination, но будет использовать дочерний класс для десериализации.

В случае, если вы хотите принудительно использовать дискриминатор для динамических экземпляров, вы можете использовать

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

Обратите внимание, что этот заголовок должен быть добавлен ко всем классам, для которых вам нужно принудительно создать дискриминатор.

0 голосов
/ 29 ноября 2018

По моему мнению, это ошибка, как вы сказали, на самом деле, учитывая исключение, которое вы упомянули, это, вероятно, ошибка.В любом случае, это GitHub-репозиторий проекта https://github.com/mongodb/mongo-csharp-driver.

В 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>,Это не красиво, но это будет работать.

...