Наследование в MongoDb: как запрашивать экземпляры определенного типа

Вот как я использовал наследование в Entity Framework (POCO):

ctx.Animals // base class instances (all instances)
ctx.Animals.OfType<Cat>  // inherited class Cat's instances only
ctx.Animals.OfType<Dog> // inherited class Dog's instances only

Это единственный подобный способ, который я нашел в MongoDb (справочник по MongoDb ):

var query = Query.EQ("_t", "Cat");
var cursor = collection.FindAs<Animal>(query);

Обратите внимание, что в последнем случае мне приходится иметь дело с дискриминатором ("_t") и жестко задавать имя моего класса, что не совсем удобно и выглядит ужасно. Если я пропущу запрос, я получу исключение при попытке перечисления. Я что-то пропустил? Мое предложение заключалось в том, что документ Db, который хранит объекты «как есть», должен легко обрабатывать наследование.


person YMC    schedule 01.05.2012    source источник


Ответы (5)


Предполагая, что ваши дискриминаторы работают (_t правильно хранится для каждого документа), я думаю, что это то, что вы ищете.

var results = collection.AsQueryable<Animal>().OfType<Cat>

Возвращает только те документы, которые относятся к типу «Cat».

person Bob Banks    schedule 17.03.2014
comment
Это правильный ответ. Вышеупомянутое переводится последним драйвером в правильный запрос монго {_t:Cat} - person Sunny Milenov; 02.10.2014

Что ж, документ БД действительно хранит объекты «как есть», то есть без понятия объектов, принадлежащих какому-то конкретному классу. Вот почему вам нужно _t, когда вы хотите, чтобы десериализатор знал, какой подкласс создавать.

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

Вы можете сделать что-то вроде этого:

public abstract class SomeBaseClass
{
    public const string FirstSubClass = "first";
    public const string SecondSubClass = "second";
}

[BsonDiscriminator(SomeBaseClass.FirstSubClass)]
public class FirstSubClass { ... }

а потом

var entireCollection = db.GetCollection<FirstSubClass>("coll");

var subs = entireCollection.Find(Query.Eq("_t", SomeBaseClass.FirstSubClass));
person mookid8000    schedule 02.05.2012
comment
+1 за предложение [BsonDiscriminator], по крайней мере, это помогает избежать жесткого кодирования - person YMC; 03.05.2012

Из вашей ссылки:

Единственный случай, когда вы должны вызвать RegisterClassMap самостоятельно (даже без аргументов), — это когда вы используете иерархию полиморфных классов: в этом случае вы должны зарегистрировать все известные подклассы, чтобы гарантировать регистрацию дискриминаторов.


Зарегистрируйте карты классов для вашего базового класса и каждого из ваших производных классов:

BsonClassMap.RegisterClassMap<Animal>();
BsonClassMap.RegisterClassMap<Cat>();
BsonClassMap.RegisterClassMap<Dog>();

Убедитесь, что ваша коллекция относится к типу вашего базового класса:

collection = db.GetCollection<Animal>("Animals");

Найдите по вашему запросу. Преобразование в соответствующий дочерний класс выполняется автоматически:

var query = Query.EQ("_t", "Cat");
var cursor = collection.Find(query);
person Jermin Bazazian    schedule 05.04.2013

Если единственной проблемой является имя класса жесткого кодирования, вы можете сделать что-то вроде этого:

collection = db.GetCollection<Animal>("Animals");
var query = Query.EQ("_t", typeof(Cat).Name);
var cursor = collection.Find(query);
person Zerdush    schedule 03.04.2014

Взгляните на документацию http://docs.mongodb.org/ecosystem/tutorial/serialize-documents-with-the-csharp-driver/#scalar-and-hierarchical-distributors

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

var query = Query.EQ("_t", "Cat");
var cursor = collection.FindAs<Animal>(query);
foreach (var cat in cursor) {
    // process cat
}
person Noam    schedule 19.08.2014