2011-01-09 12 views
5

Resulta que soy la última persona en descubrir el piso fundamental que existe en Entity Framework de Microsoft al implementar la herencia TPT (Table Per Type).Entity Framework Table por tipo Performance

Después de haber construido un prototipo con 3 subclases, la tabla base/clase que consta de más de 20 columnas y las tablas secundarias que constan de ~ 10 columnas, todo funcionó muy bien y continué trabajando en el resto de la aplicación probando concepto. Ahora ha llegado el momento de agregar los otros 20 subtipos y OMG. Acabo de comenzar a buscar el SQL generado en una selección simple, aunque solo estoy interesado en acceder a los campos de la clase base.

This page tiene una maravillosa descripción del problema.

Alguien ha entrado en producción usando TPT y EF, ¿hay algún soluciones que significa que no voy a tener a: a) convertir el esquema de TPH (que va en contra de todo lo que intento conseguir con mi Diseño de DB - urrrgghh!)? b) reescribir con otro ORM?

De la forma en que lo veo, debería poder agregar una referencia a un Procedimiento almacenado dentro de EF (probablemente utilizando EFExtensions) que tiene el TSQL que selecciona solo los campos que necesito, incluso usando el código generado por EF para el monstruo UNION/JOIN dentro del SP se evitaría que el SQL se genere cada vez que se realiza una llamada, no es algo que pretendo hacer, pero se entiende la idea.

El asesino que he encontrado, es que cuando estoy seleccionando una lista de entidades vinculadas a la tabla base (pero la entidad que estoy seleccionando no es una tabla de subclase), y quiero filtrar por el pk de la tabla Base, y hago .Include("BaseClassTableName") para permitirme filtrar usando x=>x.BaseClass.PK == 1 y acceder a otras propiedades, aquí también realiza la generación madre de SQL.

No puedo usar EF4 porque estoy limitado a los tiempos de ejecución de .NET 2.0 con 3.5 SP1 instalado.

¿Alguien ha tenido alguna experiencia para salir de este lío?

+1

no puedo hablar por EF4 previamente, pero en ese blog la afirmación "La herencia tabla-por-Type es 100% inutilizable." es un poco ridículo, al menos en EF4. Sí tiene algunos problemas de rendimiento, sí, pero si tiene 20 subtipos, ¿está seguro de haber realizado la normalización correcta de la base de datos? ¿Pueden esos 20 subtipos no dividirse en entidades padre separadas? – RPM1984

+2

Parece que otros ORM manejan el diseño TPT sin ningún problema. Con respecto al blog, establece que al implementar un diseño de base de datos/clase que tiene una gran cantidad de tipos, el tiempo que lleva generar el SQL antes de la ejecución es mayor a varios minutos, creo que es suficiente para respaldar el enunciado de ser inutilizable en un entorno de producción. Piense en un catálogo de vehículos, con información común almacenada sobre cada vehículo (la tabla base/clase) y luego información única almacenada sobre aviones/trenes/automóviles (subtabla/clase) - No estoy tratando con vehículos, pero usted obtenga la idea – Tr1stan

+1

... y allí se almacenan> 20 tipos diferentes de vehículos, incluso antes de comenzar con los subtipos de vehículos y todos los valores de búsqueda. – Tr1stan

Respuesta

1

Esto parece un poco confuso. Estás hablando de TPH, pero cuando se dice:

La forma en que lo veo, yo debería ser capaz de agregar una referencia a un procedimiento almacenado desde dentro EF (probablemente utilizando EFExtensions) que tiene el que la TSQL selecciona solo los campos que necesito, incluso usando el código generado por EF para el monstruo UNION/JOIN dentro del SP evitaría que el SQL se genere cada vez que se realiza una llamada, algo que no pretendo hacer, pero se entiende la idea.

Bueno, eso es tabla por asignación de clase de concreto (utilizando un proceso en lugar de una tabla, pero aún así, la asignación es TPC ...). El EF admite TPC, pero el diseñador no. You can do it in code-first if you get the CTP.

Su solución preferida de utilizar un proc causará problemas de rendimiento si se restringe consultas, así:

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

El optimizador de DB no puede ver a través de la ejecución Proc, por lo que obtener un análisis completo de la resultados.

Así que antes de decirse a sí mismo que esto solucionará los resultados, vuelva a verificar esa suposición.

Tenga en cuenta que siempre puede especificar SQL personalizado para cualquier estrategia de mapeo con ObjectContext.ExecuteStoreQuery.

Sin embargo, antes de hacer algo de esto, considere que, como señala RPM1984, su diseño parece sobreutilizar la herencia. Me gusta this quote from NHibernate in Action

[A] sepa si sería mejor remodelar la herencia como delegación en el modelo de objetos. La herencia compleja a menudo se evita mejor por todo tipo de razones no relacionadas con la persistencia o el ORM. [Su ORM] actúa como un búfer entre el objeto y los modelos relacionales, pero eso no significa que pueda ignorar por completo los problemas de persistencia al diseñar su modelo de objetos.

+0

Gracias Craig, solo me refería a TPH como último recurso. Lo que en realidad intento lograr es TPT. Supongo que no considero que 1 clase base/tabla y 1 nivel adicional de subclases/tablas sean herencia compleja. . Pero tal vez te estás refiriendo a que la amplitud de mi diseño de clase es demasiado "extensamente" compleja (~ 23 subclases), aunque parece que no puedo entender mejor una manera más clara de persistir en estas clases. – Tr1stan

+0

Ah, y me estaba refiriendo al método SP de consultar como una alternativa a tu sugerencia con ObjectContext.ExecuteStoreQuery. Una vez más, esperaba que me hubiera perdido algo obvio que uno de tus sabios podría haberme señalado. – Tr1stan

2

Nos hemos topado con este mismo problema y estamos considerando portar nuestra dal de EF4 a LLBLGen debido a esto.

Mientras tanto, hemos utilizado las consultas compiladas para aliviar algo del dolor:

Compiled Queries (LINQ to Entities)

Esta estrategia no impide que las consultas de mamut, pero el tiempo que se necesita para generar la consulta (que puede ser enorme) solo se hace una vez.

consultas Usted Puede utilizar compilados con Incluye() tales como:

static readonly Func<AdventureWorksEntities, int, Subcomponent> subcomponentWithDetailsCompiledQuery = CompiledQuery.Compile<AdventureWorksEntities, int, Subcomponent>(
     (ctx, id) => ctx.Subcomponents 
      .Include("SubcomponentType") 
      .Include("A.B.C.D") 
      .FirstOrDefault(s => s.Id == id)); 

    public Subcomponent GetSubcomponentWithDetails(int id) 
    { 
     return subcomponentWithDetailsCompiledQuery.Invoke(ObjectContext, id); 
    }