Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework Table Per Type Performance

So it turns out that I am the last person to discover the fundamental floor that exists in Microsoft's Entity Framework when implementing TPT (Table Per Type) inheritance.

Having built a prototype with 3 sub classes, the base table/class consisting of 20+ columns and the child tables consisting of ~10 columns, everything worked beautifully and I continued to work on the rest of the application having proved the concept. Now the time has come to add the other 20 sub types and OMG, I've just started looking the SQL being generated on a simple select, even though I'm only interested in accessing the fields on the base class.

This page has a wonderful description of the problem.

Has anyone gone into production using TPT and EF, are there any workarounds that will mean that I won't have to: a) Convert the schema to TPH (which goes against everything I try to achieve with my DB design - urrrgghh!)? b) rewrite with another ORM?

The way I see it, I should be able to add a reference to a Stored Procedure from within EF (probably using EFExtensions) that has the the TSQL that selects only the fields I need, even using the code generated by EF for the monster UNION/JOIN inside the SP would prevent the SQL being generated every time a call is made - not something I would intend to do, but you get the idea.

The killer I've found, is that when I'm selecting a list of entities linked to the base table (but the entity I'm selecting is not a subclass table), and I want to filter by the pk of the Base table, and I do .Include("BaseClassTableName") to allow me to filter using x=>x.BaseClass.PK == 1 and access other properties, it performs the mother SQL generation here too.

I can't use EF4 as I'm limited to the .net 2.0 runtimes with 3.5 SP1 installed.

Has anyone got any experience of getting out of this mess?

like image 322
Tr1stan Avatar asked Jan 09 '11 23:01

Tr1stan


1 Answers

This seems a bit confused. You're talking about TPH, but when you say:

The way I see it, I should be able to add a reference to a Stored Procedure from within EF (probably using EFExtensions) that has the the TSQL that selects only the fields I need, even using the code generated by EF for the monster UNION/JOIN inside the SP would prevent the SQL being generated every time a call is made - not something I would intend to do, but you get the idea.

Well, that's Table per Concrete Class mapping (using a proc rather than a table, but still, the mapping is TPC...). The EF supports TPC, but the designer doesn't. You can do it in code-first if you get the CTP.

Your preferred solution of using a proc will cause performance problems if you restrict queries, like this:

var q = from c in Context.SomeChild
        where c.SomeAssociation.Foo == foo
        select c;

The DB optimizer can't see through the proc implementation, so you get a full scan of the results.

So before you tell yourself that this will fix your results, double-check that assumption.

Note that you can always specify custom SQL for any mapping strategy with ObjectContext.ExecuteStoreQuery.

However, before you do any of this, consider that, as RPM1984 points out, your design seems to overuse inheritance. I like this quote from NHibernate in Action

[A]sk yourself whether it might be better to remodel inheritance as delegation in the object model. Complex inheritance is often best avoided for all sorts of reasons unrelated to persistence or ORM. [Your ORM] acts as a buffer between the object and relational models, but that doesn't mean you can completely ignore persistence concerns when designing your object model.

like image 116
Craig Stuntz Avatar answered Sep 30 '22 19:09

Craig Stuntz