EF Core - 可能会导致循环或多个级联路径

问题描述 投票:0回答:4

我已经设置了一个我认为非常简单的数据库。但是我收到以下错误。

在表“User”上引入 FOREIGN KEY 约束“FK_User_Suburb_SuburbId”可能会导致循环或多级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。 无法创建约束或索引。查看之前的错误。

这是我的目录:

using JobsLedger.CATALOG.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;

namespace JobsLedger.CATALOG
{
    public class CATALOGContext : DbContext
    {
        public DbSet<Tenant> Tenants { get; set; }
        public DbSet<User> Users { get; set; }
        public DbSet<Role> Roles { get; set; }
        public DbSet<State> States { get; set; }
        public DbSet<Suburb> Suburbs { get; set; }
        public DbSet<CATALOGCounter> Counters { get; set; }


        public CATALOGContext(DbContextOptions options) : base(options) { }



        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            foreach (var entity in modelBuilder.Model.GetEntityTypes())
            {
                entity.Relational().TableName = entity.DisplayName();
            }

            // User
            modelBuilder.Entity<User>().Property(u => u.UserName).IsRequired().HasMaxLength(50);
            modelBuilder.Entity<User>().Property(u => u.UserFirstName).IsRequired().HasMaxLength(100);
            modelBuilder.Entity<User>().Property(u => u.UserLastName).IsRequired().HasMaxLength(100);
            modelBuilder.Entity<User>().Property(u => u.Email).IsRequired().HasMaxLength(200);
            modelBuilder.Entity<User>().Property(u => u.HashedPassword).IsRequired().HasMaxLength(200);
            modelBuilder.Entity<User>().Property(u => u.Salt).IsRequired().HasMaxLength(200);

            modelBuilder.Entity<User>()
                .HasOne<Suburb>(s => s.Suburb)
                .WithMany(u => u.Users)
                .HasForeignKey(u => u.SuburbId)
                .IsRequired(false);

            // Role
            modelBuilder.Entity<Role>().Property(r => r.Name).IsRequired().HasMaxLength(50);

            modelBuilder.Entity<Role>()
                .HasOne<User>(u => u.User)
                .WithOne(r => r.Role)
                .HasForeignKey<User>(u => u.RoleId);

            // TenantAccount
            modelBuilder.Entity<Tenant>().Property(t => t.TenantNo).HasMaxLength(20);
            modelBuilder.Entity<Tenant>().Property(t => t.Company).HasMaxLength(100).IsRequired();
            modelBuilder.Entity<Tenant>().Property(t => t.ContactLastName).HasDefaultValue(false).IsRequired();
            modelBuilder.Entity<Tenant>().Property(t => t.Email).HasMaxLength(500).IsRequired();
            modelBuilder.Entity<Tenant>().Property(t => t.MobilePhone).HasMaxLength(20).IsRequired();
            modelBuilder.Entity<Tenant>().Property(t => t.OfficePhone).HasMaxLength(20);
            modelBuilder.Entity<Tenant>().Property(t => t.CompanyEmail).HasMaxLength(500);
            modelBuilder.Entity<Tenant>().Property(t => t.Address1).HasMaxLength(500);
            modelBuilder.Entity<Tenant>().Property(t => t.Address2).HasMaxLength(500);
            modelBuilder.Entity<Tenant>().Property(t => t.ABN).HasMaxLength(14);
            modelBuilder.Entity<Tenant>().Property(t => t.Database).HasMaxLength(100).IsRequired();
            modelBuilder.Entity<Tenant>().Property(t => t.IsLocked).HasDefaultValue(false);

            modelBuilder.Entity<Tenant>()
                .HasOne<User>(s => s.User)
                .WithMany(ta => ta.Tenants)
                .HasForeignKey(u => u.UserId);

            modelBuilder.Entity<Tenant>()
                .HasOne(s => s.Suburb)
                .WithMany(ta => ta.Tenants)
                .HasForeignKey(ta => ta.SuburbId);

            // State
            modelBuilder.Entity<State>().Property(s => s.StateShortName).HasMaxLength(3).IsRequired();
            modelBuilder.Entity<State>().Property(s => s.StateName).HasMaxLength(30).IsRequired();

            // Suburb
            modelBuilder.Entity<Suburb>().Property(s => s.SuburbName).HasMaxLength(3).IsRequired();
            modelBuilder.Entity<Suburb>().Property(s => s.PostCode).HasMaxLength(30).IsRequired();

            modelBuilder.Entity<Suburb>()
                .HasOne<State>(s => s.State)
                .WithMany(su => su.Suburbs)
                .HasForeignKey(st => st.StateId);
        }
    }
}

这是我的用户:

...
        public int? SuburbId { get; set; }
        public Suburb Suburb { get; set; }

        public int RoleId { get; set; }
        public Role Role { get; set; }

        public virtual ICollection<Tenant> Tenants { get; set; }

这是我的郊区,也被提到过..

想知道是否有人会强调为什么迁移会起作用,但是当我尝试启动数据库时,它会出现上述错误..

西蒙

c# entity-framework asp.net-core
4个回答
20
投票

错误已经说明了您需要做什么。指定当有一个动作时它必须做什么。您应该将

.OnDelete()
方法添加到每个外键定义中。

modelBuilder.Entity<Tenant>()
                .HasOne<User>(s => s.User)
                .WithMany(ta => ta.Tenants)
                .HasForeignKey(u => u.UserId)
                .OnDelete(DeleteBehavior.Restrict);

欲了解更多信息,请阅读https://www.learnentityframeworkcore.com/configuration/ Fluent-api/ondelete-method


5
投票

您的

User
实体
ForeignFey
Fluent API 配置应如下所示:

modelBuilder.Entity<User>()
     .HasOne<Suburb>(s => s.Suburb)
     .WithMany(u => u.Users)
     .HasForeignKey(u => u.SuburbId)
     .IsRequired(false);
     .OnDelete(DeleteBehavior.Restrict); // <-- Here it is

3
投票

对于发现这个问题的其他人来说,这就足够了:

modelBuilder.Entity<User>()
     .HasOne(u => u.Suburb)
     .WithMany(s => s.Users)
     .OnDelete(DeleteBehavior.Restrict);

如果您不想在

Suburb
中使用
Users
列出属性,您也可以这样做:

modelBuilder.Entity<User>()
     .HasOne(u => u.Suburb)
     .WithMany()
     .OnDelete(DeleteBehavior.Restrict);

0
投票

上面的答案是正确的,但让我解释一下为什么您会遇到这个问题。

基本上,User实体当前与Suburb和Role都有关系,因此不能进行级联删除,这会导致冲突。

假设您删除了一个角色,它也会删除用户,但是那么郊区呢?您现在可以看到 Suburb 没有与任何东西绑定,这就是 EF Core 阻止这种行为的原因。您必须指定 NO ACTION,以便删除角色或郊区时用户不会受到影响。 当一个实体与多个其他实体有关系时,这是一个非常常见的问题

在这种情况下,仅仅因为角色或郊区不再存在而删除用户是没有意义的。

© www.soinside.com 2019 - 2024. All rights reserved.