共有主キーを使用するときに、EFを使用したTPTアーキテクチャでは、必要なON DELETE CASCADEが作成されません... EFコンテキストがサブクラス化されたテーブルの適切な削除順序を処理するとも言われていました(ただし、制約が破られているというエラーが発生し、サブデバスにON DELETE CASCADEを追加することで修正できます)クラステーブル)...EF 4.2でのTPT(Table Per Type)の問題と親オブジェクトの削除
より多くの背景情報...
私は数、タイトル、ページのリストを持っているセクションのクラスを、持っています。このページは、基本的なページプロパティを保持するスーパークラスを使用して設計されています。私は約10 +ページクラスのサブクラスを持っています。 SectionクラスはこれらのページのICollectionを保持します。 DBはサブクラス化されたテーブルでON DELETE CASCADEを除いて正しく作成されます。
私のコードはエンティティを作成し、DBに追加します。私はセクション(または全区間)を削除しようとした場合しかし、それは私のサブクラスのページテーブルのFK制約によるtodelete ...
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; }
}
...プラス約8その他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 ...(スキーマを "" Oracle用のSQLServer、そのスキーマ名に定義されて注意してください)
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;
}
...他のモデル化するために、他のコードテーブル...
アプリはコンテンツを取り込め、関係は適切に設定されています。しかし、コースを削除しようとすると、PageContentテーブルのChapterPageの制約により、削除が失敗したというエラーが発生します。
ここでは、コースを削除するコードです(実際にすべてのコースを削除します)。 ..
using (MyContext ctx = new MyContext())
{
ctx.Courses.ToList().ForEach(crs => ctx.Courses.Remove(crs));
AttachLookupEntities(ctx);
ctx.SaveChanges();
}
私はPageContentとの共有のための主要ChapterPageとSectionPage表に 'ONは、DELETE CASCADEを' を追加した場合、削除が通過します。私が見てきた要約
、
唯一の解決策は、手動でONが私のサブクラスのページのすべてのテーブルのDELETE CASCADEを追加するために制約を変更することです。 DBを作成またはインスタンス化するためにEFを使用しないため、必要なEFテーブル用のDBスクリプトを生成するコード(DB全体の小さなサブセット)があるため、変更を実装できます(マイグレーションを適切にサポートしていないためまだ...)。
私は何かをミスコードしたり、モデルビルダーロジックの設定を忘れてしまったことを心から願っています。もしそうでなければ、EFの設計者は、実際の世界の状況ではハック回避策なしでは使用できないアーキテクチャ(TPT設計アプローチ)を定義しています。それは半完成の解決策です。私が間違ってはいけない、私はやったことが好きで、ほとんどのMSFTソリューションのように、最も基本的なアプリケーションの70%を使用しています。もっと複雑な状況には対応できません。
私は、DB設計をすべてEF流暢なAPI内に保持し、自己完結型であるようにしていました。それは私のためにそこに約98%、ちょうど彼らが仕事を終えた場合、多分次のリリースでいいだろう。少なくともCRUDの操作はすべて保存されます。
チャオ! ジム・ショー
カスケード 'Course.Chapters'、' Chapter.Sections'と 'Section.Pages'のために削除して、これらの1対多の関係が必要とされてありますかオプション?私の場合、これは、BasePagesをコンテキストにロードして明示的に削除する必要があるかのように見え、EFは2つのDELETEステートメントを作成します(ベースおよび派生テーブル用)。削除が他のエンティティの一連のカスケード削除に依存する場合、DBはEFが明らかに作成しない適切なカスケード削除を伴うすべての関連オブジェクトを削除する責任があります。私はこれをバグと呼んでいますか、少なくとも何らかの隠された制限を知っていなければなりません。 – Slauma
はいあります。私は、コンテキストを含むページのロジックを使用しようとしましたが、それでも失敗します。私は増分ではないので(EFの動的DB作成ロジックを使用することはできません)、Migrationプロジェクトが終了したときに、Add constraintsソリューションを使用することに決めました。私は、コンテキストを使用してDBスクリプトを生成するためのスクリプトジェネレータユーティリティを作成しています。別の.sqlファイルを使用してDBをモデル化します。 –