代码首先一对一启用级联删除

时间:2013-05-10 15:35:02

标签: entity-framework ef-code-first

我与外键有一对一的关系,但Cascade Delete由于某种原因未启用。示例代码如下。

public class AppRegistration
{
    public int AppRegistrationId { get; set; }
    [Required]
    [StringLength(50)]
    [Display(Name = "Username")]
    public string UserName { get; set; }
    [Required]
    [StringLength(100)]
    public string Password { get; set; }
    [StringLength(20)]
    public string StudentOrAgent { get; set; }
    // navigation properties
    public virtual AppStatus AppStatus { get; set; }
    public virtual Agreement Agreement { get; set; }
    public virtual AnotherTable AnotherTable { get; set; }
}

带有外键的从属表在下面。

public class Agreement
{
    [Key]
    [ForeignKey("AppRegistration")]
    public int AppRegistrationId { get; set; }
    public DateTime DateAgreed { get; set; }
    public virtual AppRegistration AppRegistration { get; set; }
}

当我尝试从生成的AppRegistrations表中删除一个条目时,我得到一个Reference约束冲突。

我尝试将[Required]放在依赖表中的导航属性上,但它没有做任何事情 - Update-Database命令显示No pending code-based migrations.消息。有任何想法吗?感谢。

更新 我收到以下错误消息:

The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.AppStatus_dbo.AppRegistrations_AppRegistrationId". The conflict occurred in database "MVCapp", table "dbo.AppStatus", column 'AppRegistrationId'.

2 个答案:

答案 0 :(得分:8)

我决定在单独的示例项目中解决cascade delete问题。我找到了以下博客& MSDN页面非常有用。

使用Code First方法创建以下模型。

public class Category
{
    public int CategoryId { get; set; }
    public string CategoryName { get; set; }
    public virtual Book Book { get; set; }
}
public class Book
{
    public int CategoryId { get; set; }
    public string BookTitle { get; set; }
    public string BookAuthor { get; set; }
    public string BookISBN { get; set; }
    public virtual Category Category { get; set; }
}

(我意识到实体名称暗示了一对多的关系,但我试图模仿一对一的关系,就像我在顶部的原始问题一样。)

因此,在上述模型中,每个类别只能有一个图书

DbContext - 派生类中添加以下内容。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    modelBuilder.Entity<Book>()
        .HasKey(t => t.CategoryId);

    modelBuilder.Entity<Category>()
        .HasRequired(t => t.Book)
        .WithRequiredPrincipal(t => t.Category)
        .WillCascadeOnDelete(true);
}

(以上代码需要以下命名空间:System.Data.EntitySystem.Data.Entity.ModelConfiguration.Conventions。)

这恰当地创建了一对一的关系。您将在每个表中都有一个主键,并且Book表中的外键也会启用ON DELETE CASCADE

Database Diagram for the model

在上面的代码中,Category实体使用了WithRequiredPrincipal() t => t.Category参数,其中参数是从属表中的外键列

如果您使用WithRequiredPrincipal() 而不使用参数,您将在Book表中获得额外的列,并且Book中将有两个外键}表指向CategoryId表中的Category

我希望这些信息有所帮助。

<强>更新

后来我直接在这里找到答案:

http://msdn.microsoft.com/en-us/data/jj591620#RequiredToRequired

答案 1 :(得分:7)

您没有获得级联删除的原因是因为您的关系是可选的。

如果您想要所需的关系,即AppRegistration必须有一个Agreement,您可以使用(自动配置级联删除):

public class Agreement
{
    ...
    [Required]
    public AppRegistration AppRegistration{ get; set; }
}

如果您希望通过级联删除将关系设置为可选,则可以使用Fluent API进行配置:

modelBuilder.Entity<AppRegistration>()
    .HasOptional(a => a.Agreement)
    .WithOptionalDependent()
    .WillCascadeOnDelete(true);