引入外键约束可能会导致循环或多个级联路径。

34

我遇到了这个错误:

引入“FK_dbo.Regions_dbo.Countries_CountryId”表的FOREIGN KEY限制可能导致循环或多个级联路径。请指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。无法创建约束。请参阅先前的错误。

我想知道这是否意味着我的数据库设计不好?我看到了一些关于关闭级联等操作的建议,但我并不确定这是否只是掩盖了问题。

目前我只是让EF通过我的领域类生成表格(我没有使用任何数据注释或流畅映射)。

       public class Country
        {
            public Country()
            {
                this.Stores = new List<Store>();
                this.Regions = new List<Region>();
                Id = GuidCombGenerator.GenerateComb();
            }

            public Guid Id { get; private set; }

            private string name;

            public string Name
            {
                get { return name; }
                set
                {
                    name = value.Trim();
                }
            }

            private string code;

            public string Code
            {
                get { return code; }
                set
                {
                    code = value.Trim();
                }
            }

            public virtual ICollection<Store> Stores { get; set; }
            public virtual ICollection<Region> Regions { get; set; }
        }


          public class City
        {
            public City()
            {
                this.Stores = new List<Store>();
                Id = GuidCombGenerator.GenerateComb();
            }

            public Guid Id { get; private set; }

            private string name;

            public string Name
            {
                get { return name; }
                set
                {
                    name = value.Trim();
                }
            }


            public Guid RegionId { get; set; }
            public virtual Region Region { get; set; }

            public virtual ICollection<Store> Stores { get; set; }
        }


            public class Region
        {
            public Region()
            {
                this.Cities = new List<City>();
              this.Stores = new List<Store>();


                Id = GuidCombGenerator.GenerateComb();
            }

            public Guid Id { get; private set; }


            private string state;

            public string State
            {
                get { return state; }
                set
                {
                    state = value.Trim();
                }
            }


            public Guid CountryId { get; set; }
            public virtual ICollection<City> Cities { get; set; }
            public virtual Country Country { get; set; }
           public virtual ICollection<Store> Stores { get; set; }
        }


  public class Store
    {
        public Store()
        {
            Id = GuidCombGenerator.GenerateComb();

            Users = new List<User>();
        }

        public Guid Id { get; private set; }

        public Guid CountryId { get; set; }
        public Guid CityId { get; set; }
        public Guid RegionId { get; set; }
        public virtual City City { get; set; }
        public virtual Country Country { get; set; }
        public virtual Region Region { get; set; }

        public virtual ICollection<User> Users { get; set; }

    }

是因为商店吗?


你能展示一下涉及到的表格,它们的结构是什么,最重要的是:它们之间的外键约束是如何设置的吗?所以你想在区域和国家之间建立级联删除,这样如果一个国家被删除,它所有的区域也会被删除?听起来很合理 - 问题是:为什么这会导致循环?你已经有哪些其他带有级联删除的外键约束了? - marc_s
好的,我已经更新了它以显示那些区域,因为我正在使用Code First,所以我还没有生成任何表格。 - chobo2
很遗憾,您没有展示 Store 类....而且我也没有看到任何定义级联删除的代码... - marc_s
我没有编写定义级联的代码,我只是创建了我的类,并希望Entity Framework生成所有内容。如果需要一些额外的调整,我会使用Fluent Mapping相关内容。Stores已发布。 - chobo2
3个回答

59

您的模型中所有关系都是必需的,因为所有外键属性(CountryIdRegionIdCityId)都是非空的。对于必需的一对多关系,EF将按照约定启用级联删除。

CountryRegionStore表有多个删除路径。例如,如果您删除一个Country,则相关的Store可以通过三种不同的级联路径被删除(这在SQL Server中是不允许的):

  • Country -> Store
  • Country -> Region -> Store
  • Country -> Region -> City -> Store

您必须通过使用Fluent API禁用级联删除或将某些关系定义为可选关系(带有可空的外键Guid?),以避免此类模棱两可的删除路径。

或者从除City之外的所有实体中删除Stores集合(及其反向引用和FK属性)。对我来说,这些集合看起来是冗余的,因为您可以通过导航Regions.Cities.Stores集合在一个Country中找到所有的店铺。


那么商店只与城市有关系? - chobo2
@chobo2:是的,我认为那应该足够了。 - Slauma
12
+1 信息丰富;啊,SQL Server 的这个限制真是让人恼火。在许多情况下,您有一个表实现两个表之间的多对多关系,并且您希望在关系表中将两个表都作为非空外键,并且当其中任一表被删除时,都将级联删除到关系表中。所以我想我们只能采用非常不理想的解决方案,即将其中一个外键保留为空值。要么就每次都要实现自定义触发器。真是麻烦事。 - Shavais
错误信息应该也要告诉我们表格“Store”的信息,这样我们才能知道表格“Store”存在多个删除冲突。为什么错误信息没有告诉我们呢? - Unbreakable
为什么错误信息没有提到 Store 表? - Unbreakable

25

在您的 DataContext 文件中的 OnModelCreating 方法中添加 modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(),如下所示:

public class YourDataContext : DbContext
{
    public DbSet<Country> Countries{ get; set; }
    ...


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

    }
}

同样的问题:entity-framework-how-to-solve-foreign-key-constraint-may-cause-cycles-or-multi


4
当您无法控制模式设计时,这是确切的解决方案。 - Askolein
解决方案 名词
  1. 解决问题或应对困境的方法。
- Dietrich George
我不想这样做,但我想尝试一下,结果并没有成功。我仍然遇到了OP指出的错误。 - cr1pto
我能将此转换应用于特定关系吗? - Shimmy Weitzhandler

0
dotnet ef database update --connection "{connectionStringHere}" --project {.csprojPathHere}

我曾经遇到过同样的问题,这个方法对我很有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接