未定义FK属性时,子项无法删除

时间:2012-12-14 12:27:04

标签: entity-framework entity-framework-5 delete-file

我有以下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,则删除文件。

如果我使用配置2(不需要FK属性),那么我收到错误:

  

'Context.Files'中的实体参与'File_Pack'关系。找到0个相关的'File_Pack_Target'。预计会有1'File_Pack_Target'。

为什么?在不定义FK属性时是否需要指定其他内容?

注意:我使用的是EF 5。

2 个答案:

答案 0 :(得分:2)

您定义相同关系的两种方式 - 一次使用外键属性和HasForeignKey,一次没有这样的属性和MapKey - 更改Foreign Key Association and Independent Association之间的关系类型。 / p>

使用外键关联,您可以通过设置标量属性来指定关系,即外键属性File.PackId。这个(不可为空)属性总是有一个值,无论你是否明确设置它。至少它有一个默认值0。使用外键关联,您无需设置导航属性File.Pack,以告知EF Pack File所指的Pack。 FK属性值就足够了。

另一方面,当使用独立关联时,您的模型没有外键属性,并且告诉EF与特定File相关的File.Pack的唯一方法是设置导航属性{ {1}}。

您的关系被指定为 required ,这也意味着EF希望将导航属性设置为实体并抱怨null值。这就是异常的含义。

(当你删除父实体时,不要问我为什么要拥有一个相关的实体。我不知道。实际上只有一个SQL {{1必须向父数据库发出父语句。但也许有更深层次的原因。)

因此,为了使您的代码与独立协会合作并摆脱异常,您需要设置导航属性DELETE

File.Pack

修改

BTW:您应该能够使用单个数据库查询而不是两个查询:

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();

答案 1 :(得分:0)

你的约束中有一个删除级联,这就是它删除这两个实体的原因:

add constraint Files_PackId_FK foreign key (PackId) references dbo.Packs(Id) on delete cascade on update cascade;