【问题标题】:FOREIGN KEY constraint may cause cycles or multiple cascade paths. ef core 3 (cannot create a DB at all)FOREIGN KEY 约束可能导致循环或多个级联路径。 ef core 3(根本无法创建数据库)
【发布时间】:2020-03-11 19:18:16
【问题描述】:

我收到多级联路径错误。

我的模型是 0..1 到 0..1 或者至少这是我想要达到的目标。

我的模型如下所示:

public class House
{
   public Guid Id { get; set; }

   [ForeignKey("User")]
   public User Tenant { get; set; }

public class User
{
    public House Home { get; set; }

    public Guid Id { get; set; }

我也有这个:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<House>()
        .HasOne(p => p.Tenant)
        .WithOne(t => t.Home)
        .OnDelete(DeleteBehavior.Restrict);
}   

错误不是我在删除对象时出错,它根本不会创建数据库。

我已经被告知这里已经解决了:

Entity Framework Core cascade delete one to many relationship

但是我不敢说它似乎并没有真正解决我的问题,或者我不明白它是如何解决它的。

任何帮助将不胜感激。

//更新

只是为了澄清。有许多用户/租户和许多房屋/家庭。 每个租户都可以拥有一所房子,但并非总是如此。 每个房屋都可以有一个租户,但并不总是有一个。

【问题讨论】:

  • 可以添加表的架构吗?
  • 这似乎有点奇怪......你为什么使用 ".WithOne(t=> t.Home)" ? Home 是 House 的一个实例,不是吗?所以看起来你在做一种循环引用。
  • @大卫。我承认我可能没有正确使用它。我最初根本没有 OnModelCreating。但得到级联错误。所以在查看了其他一些类似的问题之后,我得出结论我需要添加删除行为。这样当房屋或租户被删除时,记录可以设置为空。
  • 应该有其他原因(此处未显示)导致问题。或者生成的迁移是陈旧的。将有问题的 2 个类 + 完全 流畅的配置放在一个干净的新控制台项目中并生成迁移 - 不应该有级联删除约束。
  • 如果可能(我假设你正在构建你的数据库方案)我会使用更标准的 EF 系统税:每个实体中的每个 PK 都应该命名为“Id”,然后当你想引用一个“父表”(例如:House 实体有一个“User”作为租户,您只需将其(在 House 实体内)命名为“UserId”。EF 会自动理解 UserId 是指用户实体的列 ID . 这可以在没有任何 OnModelCreating 语法的情况下完成。开始简单!

标签: c# entity-framework-core


【解决方案1】:

尝试一个非常简单的方法来确定何时开始出现错误:

public class User{
   public Guid Id{get; set;}
   public string UserName{ get; set;}
}


public class House{
      public Guid Id {get; set;}
      public string StreetName {get; set;}
      public UserId {get; set;} //this should generate a foreign key to the User table
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<House>().Property(c => c.UserId).IsRequired(false);
}

这应该可以创建不需要用户存在的房屋。

【讨论】:

  • 这个简单的版本确实有效,我之前有过这个,但也需要从用户模型中引用房子。在这一点上它停止工作。根据 Ivan 的建议,我现在正在制作一个新的更简单的测试项目,以确认如果代码不在更复杂的结构中,它是否可以工作
  • 所以你应该进化到一个新模型并使用一个 UserHome 表来创建用户和主实体之间的链接。这应该有效。
【解决方案2】:

所以 1 所房子只能有 1 个租户。 1 个用户只能住在 1 个家中。您的关系是 1 对 1。在这种情况下,您可以将外键放在任一表中,但只能放在 1 个表中。那么,你就不会有循环级联的问题了。

我建议将 HouseId 放在 User 类中,这样您就可以扩展您的应用程序,以便以后可以轻松地让 1 个房子拥有许多租户。

【讨论】:

  • 我不是这样解读这段关系的。每个房屋有一个租户,每个用户有 1 个房屋。如果我有一个家,但租了另一个,两所房子都可以将我列为租户,但其中只有一个是我的家。我的阅读方式并不是说/意味着用户家必须是将用户列为租户的“1”家,所以实际上多个房子可以将同一个用户列为租户,但只有一个房子可以设置为用户的家。还是我错过了什么?
  • 我认为租户的意思是租房子的人,而不是拥有房子的人。而且,他还提到了 1..0 和 1..0 的关系。
  • 抱歉不是很清楚。有很多用户和很多房子。用户可以拥有一所房子,但并不总是拥有一所房子。房屋也可以有一个用户(租户),但并不总是有一个。
  • @Alex-TinLe 你的意思是在用户模型中根本没有对象 home 吗?只是houseid?
【解决方案3】:

这里声明了一个外键:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<House>()
        .HasOne(p => p.Tenant)
        .WithOne(t => t.Home)
        .OnDelete(DeleteBehavior.Restrict);
}  

House.Tenant 链接到User.Home。 租户是居民。不是你想要的。

你需要声明两个不同的外键:

流畅的语法

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().HasOne(u => u.Home).WithOne();
    modelBuilder.Entity<House>().HasOne(h => h.Tenant).WithOne();
}

属性语法

public class House
{
    public Guid Id { get; set; }
    [ForeignKey("TenantId")]
    public User Tenant { get; set; }
}

public class User
{
    [ForeignKey("HomeId")]
    public House Home { get; set; }
    public Guid Id { get; set; }
}

【讨论】:

  • 我试过这个,它给了我完全相同的错误。
【解决方案4】:

事实证明,Ivan 在上面的一个 cmets 中是正确的。问题实际上并不在于代码本身。事实上,在这种情况下,更简单的代码也可以工作。 该错误是由迁移引起的。我不得不删除所有迁移并从头开始。很明显,一些较旧的模型设计与这个新增加的设计发生了冲突,以至于根本不可能向前发展。必须从头开始重新创建数据库。

感谢大家的帮助。尤其是伊万和大卫。

以下是我需要做的简单模型:

public class Home
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Guid? TenantId { get; set; } 
    public Tenant Tenant { get; set; } 
}

public class Tenant
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public Home Home { get; set; } 
}

我什至不必重写 OnModelCreating。

【讨论】:

    猜你喜欢
    • 2018-08-04
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 2013-10-22
    • 2017-08-02
    相关资源
    最近更新 更多