Извлекать унаследованные экземпляры из MongoDB с помощью C # - PullRequest
5 голосов
/ 07 июня 2011

Я использую официальный драйвер MongoDb C #.

Мой сценарий: я храню объекты в MongoDb. Все объекты являются экземплярами классов, которые наследуются от одного корневого класса. Во время разработки я не знаю всех классов, которые могут быть сохранены (то есть они могут быть подключены), поэтому мне нужен какой-то способ, чтобы указать сериализатору / драйверу, как сопоставить классы с документами (дескрипторы в документе).

У кого-нибудь есть идеи?

Ответы [ 3 ]

8 голосов
/ 08 июня 2011

Официальный драйвер C # будет записывать значение дискриминатора "_t" всякий раз, когда фактический тип объекта отличается от номинального типа.Так, например:

MyRootClass obj = new MyDerivedClass();
collection.Insert(obj);

Можно также написать оператор Insert:

collection.Insert<MyRootClass>(obj);

, но компилятору проще выводить параметр типа.

Так какфактический тип obj отличается от номинального типа, на котором будет записан дискриминатор "_t".

При чтении объекта вам необходимо убедиться, что MyDerivedClass был правильно зарегистрирован:

BsonClassMap.RegisterClassMap<MyDerivedClass>();

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

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

Type myDerivedClass; // your plugged-in class
var registerClassMapDefinition = typeof(BsonClassMap).GetMethod("RegisterClassMap", new Type[0]);
var registerClassMapInfo = registerClassMapDefinition.MakeGenericMethod(myDerivedClass);
registerClassMapInfo.Invoke(null, new object[0]);

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

1 голос
/ 08 сентября 2013

Я написал вспомогательный класс, улучшающий превосходный ответ Роберта Стама и позволяющий использовать те же параметры, что и статический метод BsonClassMap.RegisterClassMap <...> ().

public class MyBsonClassMap
{
    public static void RegisterClassMap(Type type)
    {
        Type bsonClassMapType = typeof(BsonClassMap<>).MakeGenericType(new Type[] { type });
        BsonClassMap bsonClassMap = (BsonClassMap)Activator.CreateInstance(bsonClassMapType);
        BsonClassMap.RegisterClassMap(bsonClassMap);
    }

    public static void RegisterClassMap(Type type, Action<BsonClassMap> classMapInitializer)
    {
        Type bsonClassMapType = typeof(BsonClassMap<>).MakeGenericType(new Type[] { type });
        BsonClassMap bsonClassMap = (BsonClassMap)Activator.CreateInstance(bsonClassMapType);
        classMapInitializer(bsonClassMap);
        BsonClassMap.RegisterClassMap(bsonClassMap);
    }
}

Теперь я могу зарегистрировать тип, который был неизвестен во время компиляции, с почти таким же синтаксисом, что и известный:

Type unknownType; // is the type that was unknown at compile time
MyBsonClassMap.RegisterClassMap(unknownType);

или

MyBsonClassMap.RegisterClassMap(unknownType, cm =>
     cm.AutoMap());

Эти методы должны быть доступны в драйвере C #.

0 голосов
/ 07 июня 2011

Ознакомьтесь с документацией по сериализации драйверов здесь .

...