如何首先使用实体​​框架 5 代码删除具有导航属性的对象?

Posted

技术标签:

【中文标题】如何首先使用实体​​框架 5 代码删除具有导航属性的对象?【英文标题】:How can I delete an object with navigation property with entity framework 5 code first? 【发布时间】:2012-10-15 18:00:21 【问题描述】:

我首先使用的是 EF 5 代码,并且我有 2 个相关实体 ApplicationPermission 和 Application:

public class ApplicationPermission

   public virtual Application Application  get; set; 

   public int Id  get; set; 
 

public class Application 

   public string Name  get; set; 

   public int Id  get; set; 

使用以下 ApplicationPermission 映射:

HasKey(x => x.Id);
HasRequired(x => x.Application).WithMany().Map(m => m.MapKey("ApplicationId")).WillCascadeOnDelete(false);

应用:

HasKey(x => x.Id);

我使用下面的代码来删除 ApplicationPermission:

ApplicationPermission entity = new ApplicationPermission  Id = id ;
DbContext.Set<ApplicationPermission>().Attach(entity);
DbContext.Set<ApplicationPermission>().Remove(entity);
DbContext.SaveChanges();

但我在 SaveChanges 方法上遇到错误:

“CodeFirstContainer.ApplicationPermissions”中的实体参与 'ApplicationPermission_Application' 关系。 0 相关 找到了“ApplicationPermission_Application_Target”。 1 应为“ApplicationPermission_Application_Target”。

如何在不将 Application 加载到 dbcontext 的情况下删除 ApplicationPermission?

【问题讨论】:

【参考方案1】:

我相信,当您使用独立关联时,如果没有设置所需的导航属性,就不可能删除实体。您必须从数据库中加载 Application 或 - 至少 - 知道外键值并使用该值附加一个 Application 实体,如下所示:

ApplicationPermission entity = new ApplicationPermission  Id = 1 ;
entity.Application = new Application  Id = 5 ;
DbContext.Set<ApplicationPermission>().Attach(entity); //attaches Application too
DbContext.Set<ApplicationPermission>().Remove(entity);
DbContext.SaveChanges();

调用SaveChanges时生成的SQL命令为:

exec sp_executesql N'delete [dbo].[ApplicationPermissions]
where (([Id] = @0) and ([ApplicationId] = @1))',N'@0 int,@1 int',@0=1,@1=5

如您所见,delete 的查询不仅要求删除 ApplicationPermissionId,还要求删除 (and) ApplicationId 的外键值。为了成功,您必须通过使用相同的主键设置相关实体​​来了解并设置此 FK 值。

使用外键关联时不会出现问题

public class ApplicationPermission

    public virtual Application Application  get; set; 
    public int ApplicationId  get; set; 

    public int Id  get; set; 

映射:

modelBuilder.Entity<ApplicationPermission>()
    .HasRequired(x => x.Application)
    .WithMany()
    .HasForeignKey(x => x.ApplicationId)
    .WillCascadeOnDelete(false);

然后您可以使用您的原始代码,而无需将 FK 属性 ApplicationId 设置为正确的值(然后将默认为 0)并且无需设置导航属性并且删除实体将起作用。 SQL 命令不关心 FK,只查询要删除的 ApplicationPermissionId

exec sp_executesql N'delete [dbo].[ApplicationPermissions]
where ([Id] = @0)',N'@0 int',@0=1

我不知道为什么两种关联类型的 SQL 命令不同。

【讨论】:

以上是关于如何首先使用实体​​框架 5 代码删除具有导航属性的对象?的主要内容,如果未能解决你的问题,请参考以下文章

实体框架代码首先用于具有属性集合的对象

首先是实体框架代码。如何将对象类型文件的列表添加到已具有该类型属性的对象

实体框架对导航属性的约束

当延迟加载禁用时,如何通过实体框架仅将导航属性的特定属性包含到查询中?

实体框架检查属性是否为导航属性

如何在实体框架模型中使用通用导航属性?