Z tego, co rozumiem w kilku wpisach, architektura TPT, z EF, nie tworzy koniecznego NA KASKU DELETE, gdy używasz współużytkowanego klucza głównego ... Zostało również powiedziane, że kontekst EF poradzi sobie z prawidłową kolejnością usuwania podklasowanych tabel (jednak dostaję błąd, że łamie to ograniczenie i mogę je naprawić dodając NA KASKU NA KASKU klasa tabela) ...Problemy z używaniem TPT (Tabela na typ) w EF 4.2 i usuwanie obiektów nadrzędnych
więcej informacji tło ...
mam klasy sekcji, która ma numer, tytuł i listę stron. Strona została zaprojektowana przy użyciu super klasy, która zawiera podstawowe właściwości strony. Mam około 10+ podklas klasy strony. Klasa Section posiada ICollection tych stron. DB jest tworzony poprawnie, z wyjątkiem braku ON DELETE CASCADE w podklasowanych tabelach.
Mój kod utworzy encje i doda do grzywny DB. Jednak, gdy próbuję usunąć sekcję (lub wszystkie sekcje) nie powiedzie todelete ze względu na ograniczenie FK na moim podklasy widoku tabeli ...
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; }
}
... plus około 8 innych BasePage podklasy ...
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; }
...
}
.. Fluent API ... (uwaga Schema jest zdefiniowana "" dla SqlServer, Oracle jego nazwa schematu)
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;
}
... inny kod inny model stoły ...
Dzięki temu aplikacja może wypełniać treść, a relacje są poprawnie skonfigurowane. Jednak, gdy próbuję usunąć kurs, pojawia się błąd, że usunięcie nie powiodło się z powodu ograniczenia w tabeli ChapterPage do PageContent.
Oto kod, który usuwa Kurs (w rzeczywistości usuwam wszystkie kursy). ..
using (MyContext ctx = new MyContext())
{
ctx.Courses.ToList().ForEach(crs => ctx.Courses.Remove(crs));
AttachLookupEntities(ctx);
ctx.SaveChanges();
}
jeśli dodać 'ON DELETE CASCADE' w tabeli ChapterPage i SectionPage za wspólną podstawowej z PageContent, kasowania przechodzi.
Podsumowując,
Jedynym rozwiązaniem, które widziałem jest ręcznie zmieniać ograniczeń dodać ON DELETE CASCADE do wszystkich moich podklasa tablice stron. Mogę zaimplementować zmianę, ponieważ mam kod, który generuje skrypt DB dla potrzebnych tabel EF (mały podzbiór naszego całego DB), ponieważ nie będziemy używać EF do tworzenia lub tworzenia instancji DB (ponieważ nie obsługuje ona poprawnie migracji na razie...).
Mam szczerą nadzieję, że coś źle zinterpretowałem lub zapomniałem jakiegoś ustawienia w logice budującego model. Bo jeśli nie, projektanci EF zdefiniowali architekturę (podejście do projektowania TPT), której nie można zastosować w żadnej realnej sytuacji bez obejścia zabezpieczeń. To w połowie gotowe rozwiązanie. Nie zrozumcie mnie źle, podoba mi się praca, która została wykonana, i jak większość rozwiązań MSFT działa na 70% najbardziej podstawowych zastosowań aplikacji. Po prostu nie jest gotowy na bardziej złożone sytuacje.
Próbowałem zachować projekt DB w płynnym API EF i samodzielny. Dla mnie jest to 98%, byłoby miło, gdyby zakończyli pracę, może w następnym wydaniu. Przynajmniej to oszczędza mi wszystkich operacji CRUD.
Ciao! Jim Shaw
Czy istnieje kaskadowe usuwanie do '' Chapter.Sections' Course.Chapters' i 'Section.Pages' i są te jeden-do-wielu relacje wymagane lub opcjonalny? Dla mnie wygląda to tak, jakby trzeba było wczytać strony Base do kontekstu, a następnie usunąć je explicitely i EF tworzy następnie dwie instrukcje DELETE (dla tabeli bazowej i pochodnej). Jeśli usuwanie polega na łańcuchu kaskadowych usunięć innych elementów, DB jest odpowiedzialny za usunięcie wszystkich powiązanych obiektów z odpowiednimi kaskadowymi usunięciami, których EF najwyraźniej nie tworzy. Nazwałbym to błędem lub przynajmniej jakimś ukrytym ograniczeniem, o którym trzeba wiedzieć. – Slauma
Tak, jest. Próbowałem użyć kontekstu w logice Include pages, ale nadal nie działa. Postanowiłem zastosować rozwiązanie Add constraints, ponieważ nie będziemy/mogli używać logiki EF Dynamic DB tworzenia, ponieważ nie jest ona przyrostowa (być może po zakończeniu projektu migracji). Pisałem narzędzie generatora skryptów do użycia skryptu db pisać kontekst i niektóre automatycznie generowane skrypty kasowania w celu zwiększenia db skryptu). Będziemy używać oddzielnego pliku .sql do modelowania DB ... –