The Problem
When using Entity Framework let’s say you set up a model with inheritance. Let’s make ourselves a simple example (with psuedo-code) to illustrate:
abstract class Product
{
int Id { get; private set; }
ICollectionItems { get; set; }
}
class Good : Product { }
class Service : Product { }
class ProductItem
{
int Id { get; private set; }
string Name { get; set; }
//assume we have a navigation property
Product Product { get; set; }
int ProductId { get; set; }
}
Basically we have our inherited entity Product, and another entity ProductItem that has a navigation property to a Product. Now if you were to want to query products of only a certain type (say we only want to load services, like our company’s delicious duo of “Bacon Frying” and “Bacon Delivery” services), you might do something like this (using LINQ, assuming a DataContext/ObjectContext named ctx):
IQueryable= from s in ctx.Products.OfType () select s;
That’s all standard, well, and good. But what if you want to query from the ProductItem’s point of view so we can query item’s properties easier? You could of course do something like this:
IQueryable= from s in ctx.Products.OfType ().Include("Items") where s.Items.Any(i => i.Name.Contains("bacon")) select s;
but….there are still times you want to query starting with the items. Something like this:
IQueryable= from i in ctx.ProductItems.Include("Product") select i;
How do we do this except restrict ourselves to only loading items for services? OfType only works on collections, not navigation properies….
A Solution
The solution I found ended up being surprisingly simple – so simple it took me a long time to figure it out as I originally thought there was no way it would work:
IQueryable= from i in ctx.ProductItems.Include("Product") where (i.Product as Service) != null && i.Name.Contains("bacon") select i;
You simply cast the navigation property with the “as” keyword and check for null. This works as you would expect- Entity Framework detects this and adds the SQL to filter when the product type is a service only. I’ve only tested this with a TPH (Type per Hierarchy) strategy but I would expect it to work with TPT (Type per Table) as well. Color me impressed.
Sugoi Kantandane…