实体框架级联删除

时间:2014-11-11 17:09:40

标签: entity-framework

首先,如果我在这里遗漏了一些基本的东西,我很抱歉,但我是EF的新手,并且仍然首先考虑设置数据库代码......

我遇到类似的问题Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths但似乎无法从那些我需要对我的特定模型做的评论中找到答案。在我将public virtual Actor actor { get; set; }添加到我的UseCase类后尝试更新数据库时,出现此错误:

Introducing FOREIGN KEY constraint 'FK_dbo.UseCase_dbo.Actor_ActorID' on table 'UseCase' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.

我知道它必须与我的FK约束的设置方式有关(可能与删除用例有关,这意味着我将最终删除多个其他表中的数据)。

我尝试关闭级联删除,但仍然收到错误:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //prevent table names created by entity framework being pluralised
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            //Turn off delete cascades between parent child tables. May need to put this back in future, but for the time being it is stopping the database being updated through the package manager console (error is that a foregin key constraint may cause cycles or multiple cascade paths) 
            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
            modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
        }

这是我的模特。应该发生的是,只有在项目被删除的情况下才应删除用例或参与者。当使用UseCase时,不应删除Actor,因为它们可能涉及其他UseCases。谁能指出我需要改变的东西?

最后,正确的模型确实是这个Project > Actors > Use Cases。我假设我应该从UseCase中删除public virtual int ProjectID { get; set; }public virtual Project project { get; set; }

学习伤害!

 public class Project
    {
        public virtual int ID {get; set;}
        [DisplayName ("Project Name")]
        public virtual string ProjectName { get; set; }
        [DisplayName("Client")]    
        public virtual string ClientID { get; set; }
        public virtual string Description { get; set; }
        [DisplayName("Use Cases")]
        public virtual ICollection <UseCase> UseCases { get; set; } 

   }

public class UseCase

{
    public virtual int ID { get; set; }
    [Required]
    public virtual int ProjectID { get; set; }
    public virtual int ActorID { get; set; }
    [Required]
    public virtual Actor actor { get; set; }
    public virtual string Title { get; set; }
    public virtual Level? Level { get; set; }
    public virtual string Precondition { get; set; }
    public virtual string MinimalGuarantee { get; set; }
    public virtual string SuccessGuarantee { get; set; }
    public virtual ICollection<Step> Steps { get; set; }
    public virtual ICollection<Extension> Extensions { get; set; }
    public virtual ICollection<Query> Queries { get; set; }

}

public class Actor
{
    public virtual int ID { get; set; }
    public virtual int projectID { get; set; }
    public virtual Project project { get; set; } 
    public virtual string Title { get; set; }

    [DataType(DataType.MultilineText)]
    public virtual string Description { get; set; }

}

更新所以,这是我修改过的代码,基于以下反馈。当我运行应用程序并尝试创建数据库或尝试通过包管理器Update-Database更新数据库时,我仍然会收到相同的错误。快把我逼疯了。

对我来说,下面的代码说如果删除一个actor,也要删除该actor的用例。如果我删除项目,删除项目的actor,因此也删除每个actor的用例。但是如果删除项目,请不要删除用例。显然,我误解了一些非常糟糕的事情:-(

    modelBuilder.Entity<Actor>()
    .HasMany(a => a.useCases)
    .WithRequired(uc => uc.actor)
    .HasForeignKey(uc => uc.ActorID)
    .WillCascadeOnDelete(true); // and this works

    modelBuilder.Entity<Project>()
    .HasMany(p => p.actors)
    .WithRequired(a => a.project)
    .HasForeignKey(a => a.projectID)
    .WillCascadeOnDelete(true); // this works

    modelBuilder.Entity<Project>()
    .HasMany(p => p.UseCases)
    .WithRequired(uc => uc.project)
    .HasForeignKey(uc => uc.ProjectID)
    .WillCascadeOnDelete(false); // disable this cascading delete

2 个答案:

答案 0 :(得分:2)

您需要为除一个可能路径之外的所有路径禁用级联删除。在您的情况下,您有以下路径:

Project -> UseCase
Project -> Actor -> UseCase

您可以通过UseCase实体或Project实体允许单个路径级联删除Actor。但是,如果我们在Project - &gt;中禁用级联删除操作UseCase路径,我们仍会通过Actor实现级联删除:

modelBuilder.Entity<Project>()
    .HasMany( p => p.UseCases )
    .WithRequired( uc => uc.Project )
    .HasForeignKey( uc => uc.ProjectID )
    .WillCascadeOnDelete( false ); // disable this cascading delete

modelBuilder.Entity<Project>()
    .HasMany( p => p.Actors )
    .WithRequired( a => a.Project )
    .HasForeignKey( a => a.ProjectID )
    .WillCascadeOnDelete( true ); // this works

modelBuilder.Entity<Actor>()
    .HasMany( a => a.UseCases )
    .WithRequired( uc => uc.Actor )
    .HasForeignKey( uc => uc.ActorID )
    .WillCascadeOnDelete( true ); // and this works

旁注:

您的模型存在数据不一致危险 - ActorUseCase都通过Project获得FK到ProjectID,但模型中没有任何内容可以强制执行Actor UseCase引用的{1}}具有相同的ProjectID - 来自“项目1”的Actor可以由来自“项目2”的UseCase引用。您可以在ProjectID PK中加入Actor,然后在UseCase - &gt; Actor FK中加入,以确保Actor引用UseCase }}属于同一Project,但这在技术上会违反2NF

'正确'模型可能是Project - &gt; Actors - &gt; UseCases层次结构,只需要您通过Actors加入Project 1}} UseCase s

答案 1 :(得分:0)

您需要在ActorID类中将UseCase作为可以为空的int。 EF抛出该错误是因为它看到了单个类中需要的2个外键。有了它会创建多个级联路径 - 遗憾的是,SQL Server无法处理。

在任何情况下,在Actor课程中设置UseCase可选意味着ActorUseCase出现时不会被删除,我相信是你的意图。

相关问题