Por lo que entiendo en varias publicaciones, el TFT architecure, con EF, no crea el CASCADE EN ELIMINAR necesario al usar una clave primaria compartida ... También se dijo que el contexto EF manejará el orden correcto de eliminación de las tablas sub-clasificadas (sin embargo, obtengo un error que rompe la restricción y que puedo solucionarlo añadiendo ON DELETE CASCADE en el sub- tabla de clase) ...Problemas al utilizar TPT (tabla por tipo) en EF 4.2 y eliminación de objetos principales
más información de fondo ...
tengo una clase de sección, que tiene un número, título y una lista de páginas. La página está diseñada usando una súper clase que contiene propiedades básicas de la página. Tengo aproximadamente 10+ subclases de la clase de página. La clase Section contiene una colección de estas páginas. El DB se crea correctamente con la excepción de no ON DELETE CASCADE en las tablas sub-clasificadas.
Mi código creará las entidades y las agregará a la multa de DB. Sin embargo, si intento eliminar una sección (o todas las secciones) se produce un error todelete debido a la restricción FK en mi tabla de páginas subclase ...
public abstract BaseContent
{
... common properties which are Ignored in the DB ...
}
public class Course : BaseContent
{
public int Id {get;set;}
public string Name {get;set;}
public string Descripiton {get;set;}
public virtual ICollection<Chapter> Chapters{get;set;}
...
}
public class Chapter : BaseContent
{
public int Id {get;set;}
public int Number {get;set;}
public string Title {get;set;}
public virtual Course MyCourse{get;set;}
public virtual ICollection<Section> Sections{get;set;}
...
}
public class Section : BaseContent
{
public int Id {get;set;}
public int Number {get;set;}
public string Title {get;set;}
public virtual Chapter MyChapter {get;set;}
public virtual ICollection<BasePage> Pages {get;set;}
...
}
public abstract class BasePage : BaseContent, IComparable
{
public int Id { get; set; }
public string Title { get; set; }
public string PageImageRef { get; set; }
public ePageImageLocation ImageLocationOnPage { get; set; }
public int PageNumber { get; set; }
public virtual Section MySection { get; set; }
...
}
public class ChapterPage : BasePage
{
public virtual int ChapterNumber { get; set; }
public virtual string ChapterTitle { get; set; }
public virtual string AudioRef { get; set; }
}
public class SectionPage : BasePage
{
public virtual int SectionNumber { get; set; }
public virtual string SectionTitle { get; set; }
public virtual string SectionIntroduction { get; set; }
}
... además de unos 8 otras subclases BasePage ...
public class MyContext: DbContext
{
...
public DbSet<Course> Courses { get; set; }
public DbSet<Chapter> Chapters { get; set; }
public DbSet<Section> Sections { get; set; }
public DbSet<BasePage> Pages { get; set; }
...
}
.. API Fluido ... (esquema nota se define en "" para SqlServer, Oracle para su el nombre de esquema)
private EntityTypeConfiguration<T> configureTablePerType<T>(string tableName) where T : BaseContent
{
var config = new EntityTypeConfiguration<T>();
config.ToTable(tableName, Schema);
// This adds the appropriate Ignore calls on config for the base class BaseContent
DataAccessUtilityClass.IgnoreAllBaseContentProperties<T>(config);
return config;
}
public virtual EntityTypeConfiguration<BasePage> ConfigurePageContent()
{
var config = configureTablePerType<BasePage>("PageContent");
config.HasKey(pg => pg.Id);
config.HasRequired(pg => pg.Title);
config.HasOptional(pg => pg.PageImageRef);
config.Ignore(pg => pg.ImageLocationOnPage);
return config;
}
public virtual EntityTypeConfiguration<ChapterPage> ConfigureChapterPage()
{
var config = configureTablePerType<ChapterPage>("ChapterPage");
config.HasOptional(pg => pg.AudioRef);
config.Ignore(pg => pg.ChapterNumber);
config.Ignore(pg => pg.ChapterTitle);
return config;
}
public virtual EntityTypeConfiguration<SectionPage> ConfigureSectionPage()
{
var config = configureTablePerType<SectionPage>("SectionPage");
config.HasOptional(pg => pg.AudioRef);
config.Ignore(pg => pg.SectionNumber);
config.Ignore(pg => pg.SectionTitle);
return config;
}
... otro código para modelar otra tablas ...
De modo que la aplicación puede llenar el contenido y las relaciones están configuradas correctamente. Sin embargo, cuando intento eliminar el curso, aparece el error de que la eliminación falló debido a la restricción en la tabla ChapterPage to PageContent.
Aquí está el código que borra el curso (en realidad elimino todos los cursos). ..
using (MyContext ctx = new MyContext())
{
ctx.Courses.ToList().ForEach(crs => ctx.Courses.Remove(crs));
AttachLookupEntities(ctx);
ctx.SaveChanges();
}
Si añado el 'ON DELETE CASCADE' en la tabla ChapterPage y SectionPage por su principal compartida con PageContent, la eliminación pasa por.
En resumen,
La única solución que he visto es alterar manualmente las restricciones para añadir el ON DELETE CASCADE para todos mis tablas de páginas sub-clase. Puedo implementar el cambio, ya que tengo un código que genera el script DB para las tablas EF que necesito (un pequeño subconjunto de nuestro DB completo) ya que no usaremos EF para crear o crear instancias del DB (ya que no admite migraciones adecuadas todavía...).
Sinceramente espero haber codificado mal algo, u olvidé alguna configuración en la lógica del generador de modelos. Porque si no, los diseñadores de EF han definido un enfoque de diseño de arquitectura (TPT) que no se puede usar en ninguna situación del mundo real sin una solución de hack. Es una solución a medio terminar. No me malinterprete, me gusta el trabajo que se ha realizado y, como la mayoría de las soluciones de MSFT, funciona con el 70% de los usos de aplicaciones más básicos. Simplemente no está listo para situaciones más complejas.
Estaba tratando de mantener el diseño de la base de datos dentro de la API EF fluida y autónomo. Me espera un 98%, sería bueno si terminaran el trabajo, tal vez en el próximo lanzamiento. Al menos me ahorra todas las operaciones CRUD.
Ciao! Jim Shaw
¿Hay eliminar una cascada para 'Course.Chapters',' 'Chapter.Sections' y Section.Pages' y son estas relaciones uno-a-muchos o requeridos ¿Opcional? Para mí esto parece como si uno tuviera que cargar las páginas base en el contexto y luego eliminarlas explícitamente y EF crea entonces dos declaraciones DELETE (para la tabla base y la tabla derivada). Si la eliminación se basa en una cadena de eliminaciones en cascada de otras entidades, el DB es responsable de eliminar todos los objetos relacionados con las eliminaciones en cascada adecuadas que aparentemente EF no crea. Llamaría a esto un error o al menos algún tipo de limitación oculta que uno debe conocer. – Slauma
Sí, hay. Traté de que el contexto utilizara la lógica Incluir páginas, pero aún falla. Decidí ir con la solución Agregar restricciones, ya que usaremos/no podremos usar la lógica de creación de DB dinámica de EF ya que no es incremental (tal vez cuando finalice el proyecto de migraciones). He estado escribiendo una utilidad de generación de scripts para usar el script de escritura contextual db y algunos scripts de eliminación en cascada generados automáticamente para aumentar el script db). Vamos a utilizar un archivo .sql por separado para modelar el DB ... –