Inheritance in MongoDb: how to request instances of defined type

后端 未结 5 1942
时光说笑
时光说笑 2021-02-10 16:41

This is how I used to utilize inheritance in Entity Framework (POCO):

ctx.Animals // base class instances (all instances)
ctx.Animals.OfType  // inher         


        
相关标签:
5条回答
  • 2021-02-10 17:03

    Take a look on the documentation http://docs.mongodb.org/ecosystem/tutorial/serialize-documents-with-the-csharp-driver/#scalar-and-hierarchical-discriminators

    The main reason you might choose to use hierarchical discriminators is because it makes it possibly to query for all instances of any class in the hierarchy. For example, to read all the Cat documents we can write:

    var query = Query.EQ("_t", "Cat");
    var cursor = collection.FindAs<Animal>(query);
    foreach (var cat in cursor) {
        // process cat
    }
    
    0 讨论(0)
  • 2021-02-10 17:06

    From your link:

    The one case where you must call RegisterClassMap yourself (even without arguments) is when you are using a polymorphic class hierarchy: in this case you must register all the known subclasses to guarantee that the discriminators get registered.


    Register class maps for your base class and each one of your derived classes:

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

    Make sure that your collection is of type of your base class:

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

    Find using your query. The conversion to the corresponding child class is done automatically:

    var query = Query.EQ("_t", "Cat");
    var cursor = collection.Find(query);
    
    0 讨论(0)
  • 2021-02-10 17:20

    If the only concern is hardcoding class name, you can do something like this:

    collection = db.GetCollection<Animal>("Animals");
    var query = Query.EQ("_t", typeof(Cat).Name);
    var cursor = collection.Find(query);
    
    0 讨论(0)
  • 2021-02-10 17:25

    Well, a document db does in fact store objects "as is" - i.e. without the notion of objects belonging to some particular class. That's why you need _t when you want the deserializer to know which subclass to instantiate.

    In your case, I suggest you come up with a discriminator for each subclass, instead of relying on the class name. This way, you can rename classes etc. without worrying about a hardcoded string somewhere.

    You could do something like this:

    public abstract class SomeBaseClass
    {
        public const string FirstSubClass = "first";
        public const string SecondSubClass = "second";
    }
    
    [BsonDiscriminator(SomeBaseClass.FirstSubClass)]
    public class FirstSubClass { ... }
    

    and then

    var entireCollection = db.GetCollection<FirstSubClass>("coll");
    
    var subs = entireCollection.Find(Query.Eq("_t", SomeBaseClass.FirstSubClass));
    
    0 讨论(0)
  • 2021-02-10 17:28

    Assuming your discriminators are functioning (_t is stored correctly for each document) then I think this is what you are looking for.

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

    Returns only those documents that are of type 'Cat'.

    0 讨论(0)
提交回复
热议问题