RavenDB version 2.5. Other versions:

Polymorphic indexes

By default, RavenDB indexes operate only on a specific entity type, or a Collection, and it ignores the inheritance hierarchy when it does so.

For example, let us assume that we have the following inheritance hierarchy:

Figure 1: Polymorphic indexes

If we saved a Cat, it would have an Entity-Name of "Cats" and if we saved a Dog, it would have an Entity-Name of "Dogs".

If we wanted to index cats by name, we would write:

    from cat in docs.Cats
    select new { cat.Name }

And for dogs:

    from dog in docs.Dogs
    select new { dog.Name }

This works, but each index would only give us results for the animal it has been defined on. But what if we wanted to query across all animals?

Multi-map indexes

The easiest way to do this is by writing a multi-map index like this one:

    public class AnimalsIndex : AbstractMultiMapIndexCreationTask
    {
    	public AnimalsIndex()
    	{
    		AddMap<Cat>(cats => from c in cats
    							select new { c.Name });
    
    		AddMap<Dog>(dogs => from d in dogs
    							select new { d.Name });
    	}
    }
    
    

And query it like this:

    var results = session.Advanced.LuceneQuery<object>("AnimalsIndex").WhereEquals("Name", "Mitzy");
    
    

You can also use the Linq provider if your objects implement an interface, IAnimal for instance:

    session.Query<IAnimal>("AnimalsIndex").Where(x => x.Name == "Mitzy");
    
    

Other ways

Another option would be to modify the way we generate the Entity-Name for subclasses of Animal, like so:

    var documentStore = new DocumentStore()
    {
    	Conventions =
    	{
    		FindTypeTagName = type =>
    		{
    			if (typeof(Animal).IsAssignableFrom(type))
    				return "Animals";
    			return DocumentConvention.DefaultTypeTagName(type);
    		}
    	}
    };
    
    

Using this method, we can now index on all animals using:

    from animal in docs.Animals
    select new { animal.Name }

But what happen when you don't want to modify the entity name of an entity?

You can create a polymorphic index using:

    from animal in docs.WhereEntityIs("Cats", "Dogs")
     select new { animal.Name }

That would generate an index that would match both Cats and Dogs.

Comments add new comment

The comments section is for user feedback or community content. If you seek assistance or have any questions, please post them at our support forums.

Sean Kearon
REPLY Posted by Sean Kearon on

There is some discussion of how to create polymorphic indexes without having to change the index each time you add a subclass in this thread:

https://groups.google.com/forum/?fromgroups#!topic/ravendb/eFUlQG-spzE

Matt Johnson
REPLY Posted by Matt Johnson on

The part about needing an IAnimal interface is incorrect. You can just use the Animal abstract class. You can even use it instead of object in the lucene query. Works on 1.0 and 2.0. Probably don't even need to talk about lucene query here.

SUBMIT COMMENT