【问题标题】:code first one-to-one enable cascade delete代码优先一对一启用级联删除
【发布时间】:2013-05-10 15:35:01
【问题描述】:

我与外键有一对一的关系,但由于某种原因没有启用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 表中删除一个条目时,我遇到了引用约束冲突。

我尝试将[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'.

【问题讨论】:

    标签: entity-framework ef-code-first


    【解决方案1】:

    我决定在一个单独的示例项目中解决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; }
    }
    

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

    因此,在上述模型中,每个 Category 只能有一本 Book。

    在您的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.Entity、System.Data.Entity.ModelConfiguration.Conventions。)

    这正确地创建了一对一的关系。每个表中都有一个主键,Book 表中还有一个外键,启用了ON DELETE CASCADE。

    在上面的代码中,在Category实体上我使用了WithRequiredPrincipal() with t =&gt; t.Category参数,其中参数是依赖表中的外键列。

    如果您使用WithRequiredPrincipal() 没有参数,您将在Book 表中获得一个额外的列,并且您将在Book 表中拥有两个指向@987654341 的外键@ 在Category 表中。

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

    更新

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

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

    【讨论】:

      【解决方案2】:

      你没有得到级联删除的一个原因是你的关系是可选的。

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

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

      如果您希望关系是可选的级联删除,您可以使用 Fluent API 进行配置:

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

      【讨论】:

      • 感谢您的回答。我尝试输入[Required],但代码迁移的Update-Database 返回No pending code-based migrations. 有什么办法可以解决这个问题?
      • 我可能错了,但我认为您不会想尝试第一种技术,因为几乎不可能满足双向所需的一对一关系。如果你尝试插入协议,你会因为 AppRegistration 不存在而违反约束,反之亦然。
      • @user2291748 您是否在运行更新数据库之前添加了迁移? AaronLS,嗯,也许你是对的,这只是我想到的。
      • @MattSull87 我确实添加了迁移。在遇到问题之前,我已经多次使用 update-database。
      • 在OnModelCreating() 中运行Fluent API 代码在AppRegistrations 表中添加了一列并将其标记为外键。但外键应该在Agreements 表中。
      猜你喜欢
      • 1970-01-01
      • 2014-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多