问题
This is how I used to utilize inheritance in 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
This is the only similar way I found in MongoDb (MongoDb reference):
var query = Query.EQ("_t", "Cat");
var cursor = collection.FindAs<Animal>(query);
Note in the latter case I have to deal with discriminator ("_t") and hardcode my class name, that is not quite convenient and looks awful. If I miss the query I got an exception on enumeration attempt. Have I missed something? My suggestion was the document Db which stores objects 'as is' should handle inheritance easily.
回答1:
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'.
回答2:
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));
回答3:
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);
回答4:
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);
回答5:
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
}
来源:https://stackoverflow.com/questions/10405887/inheritance-in-mongodb-how-to-request-instances-of-defined-type