1

次のSQLテーブルがあります(簡単にするために列を削除しました)。

create table dbo.Packs 
(
  Id int identity not null
    constraint Packs_Id_PK primary key clustered (Id)
);
create table dbo.Files
(
  Id int identity not null
    constraint Files_Id_PK primary key clustered (Id),
  PackId int not null
);
alter table dbo.Files
add constraint Files_PackId_FK foreign key (PackId) references dbo.Packs(Id) on delete cascade on update cascade;

次に、次のようにPocosを作成しました。

public class Pack {
  public Int32 Id { get; set; }
  public virtual ICollection<File> Files { get; set; }
} // Pack
public class File {
  public Int32 Id { get; set; }
  public int PackId { get; set; } 
  public virtual Pack Pack { get; set; }
} // File

そして、構成は次のとおりです。

internal class PackMapper : EntityTypeConfiguration<Pack> {
  internal PackMapper()
    : base() {

    ToTable("Packs");
    HasKey(x => x.Id);

    Property(x => x.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
  }
} // PackMapper

internal class FileMapper : EntityTypeConfiguration<File> {
  internal FileMapper()
    : base() {

    ToTable("Files");
    HasKey(x => x.Id);

    Property(x => x.Id).IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    // 1 > CONFIGURATION WITH FK IN ENTITY   
    Property(x => x.PackId).HasColumnName("PackId").IsRequired();
    HasRequired(x => x.Pack).WithMany(x => x.Files).HasForeignKey(x => x.PackId);

    // 2 > CONFIGURATION WITHOUT FK IN ENTITY
    // HasRequired<Pack>(x => x.Pack).WithMany(y => y.Files).Map(z => { z.MapKey("PackId"); });
   }
 } // FileMapper

それから私はファイルを削除しようとしました:

Pack pack = context.Packs.First(x => x.Id == 31);
 IList<Int32> ids = context.Entry<Pack>(pack).Collection(x => x.Files).Query().Select(x => x.Id).ToList();
foreach (int id in ids) {
  File file = new File() { Id = id };
  context.Files.Attach(file);
  context.Files.Remove(file);
}
context.SaveChanges();

構成1を使用すると、ファイルが削除されます。

(FKプロパティを必要とせずに)構成2を使用すると、次のエラーが発生します。

'Context.Files'のエンティティは、'File_Pack'関係に参加します。0個の関連する「File_Pack_Target」が見つかりました。1'File_Pack_Target'が必要です。

何故ですか?FKプロパティを定義しない場合、他に何かを指定する必要がありますか?

注:私はEF5を使用しています。

4

2 に答える 2

2

同じ関係を定義する 2 つの方法 (外部キー プロパティを使用する場合とHasForeignKeyそのようなプロパティを使用しない場合) を定義し、外部キー アソシエーションと独立アソシエーションMapKeyの間のリレーションシップのタイプを変更します。

外部キー アソシエーションを使用すると、スカラー プロパティ、つまり外部キー プロパティを設定することで関係を指定できますFile.PackId。この (null 非許容) プロパティは、明示的に設定するかどうかに関係なく、常に値を持ちます。少なくともデフォルト値があります0。外部キー アソシエーションを使用すると、どのa が参照されているFile.Packかを EF に伝えるために、ナビゲーション プロパティを設定する必要はありません。FK プロパティ値で十分です。PackFile

一方、独立した関連付けを使用する場合、モデルには外部キー プロパティがなくPack、特定のものに関連するものを EF に伝える唯一の方法Fileは、ナビゲーション プロパティを設定することFile.Packです。

あなたの関係は必須として指定されています。これは、EF がナビゲーション プロパティをエンティティに設定し、null値について不平を言うことも意味します。それが例外の意味です。

(親エンティティを削除するときに、関連するエンティティが必要な理由を聞かないでください。わかりません。DELETE親の SQL ステートメントだけをデータベースに発行する必要がある場合は、実際には問題にならないはずです。しかし、もっと深い理由があるのか​​もしれません。)

したがって、コードを独立した関連付けで動作させ、例外を取り除くには、ナビゲーション プロパティを設定する必要がありますFile.Pack

Pack pack = context.Packs.First(x => x.Id == 31);
IList<Int32> ids = context.Entry<Pack>(pack).Collection(x => x.Files).Query()
    .Select(x => x.Id).ToList();
foreach (int id in ids) {
    File file = new File() { Id = id, Pack = pack };
    context.Files.Attach(file);
    context.Files.Remove(file);
}
context.SaveChanges();

編集

ところで: 2 つのクエリではなく、1 つのデータベース クエリを使用できるはずです。

IList<Int32> ids = context.Files.Where(f => f.Pack.Id == 31)
    .Select(f => f.Id).ToList();
Pack pack = new Pack { Id = 31 };
foreach (int id in ids) {
    File file = new File { Id = id, Pack = pack };
    context.Files.Attach(file);
    context.Files.Remove(file);
}
context.SaveChanges();
于 2012-12-14T18:59:13.197 に答える
0

制約に削除カスケードがあるため、両方のエンティティが削除されます。

add constraint Files_PackId_FK foreign key (PackId) references dbo.Packs(Id) on delete cascade on update cascade;
于 2012-12-14T12:31:15.623 に答える