see on GitHub

Indexing polymorphic data

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

For example, let's 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 }

Although it works, 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 Animals_ByName : AbstractMultiMapIndexCreationTask
{
	public Animals_ByName()
	{
		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:

List<object> results = session
	.Advanced
	.DocumentQuery<object, Animals_ByName>()
	.WhereEquals("Name", "Mitzy")
	.ToList();

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

IList<IAnimal> results = session
	.Query<IAnimal, Animals_ByName>()
	.Where(x => x.Name == "Mitzy")
	.ToList();

Other ways

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

DocumentStore store = 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 happens when you don't want to modify the entity name of an entity itself?

You can create a polymorphic index using:

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

It will generate an index that matches both Cats and Dogs.