【问题标题】:.Net Entity Framework Introducing FOREIGN KEY constraint exception.Net Entity Framework 引入 FOREIGN KEY 约束异常
【发布时间】:2017-12-20 12:57:33
【问题描述】:

这是我的一个数据库,根据代码优先原则创建: 我有一个抽象类Client(在我的数据库中创建了这个类的一个表):

    public abstract class Client
    {
        public int ClientId { get; set; }

        [Required(ErrorMessage = "Name is required for Client")]
        public string ClientName { get; set; } // name

        [Required(ErrorMessage = "Phone number is required for Client")]
        public string ClientPhoneNumber { get; set; } // phone number

        public string Email { get; set; } // email

        public string Comment { get; set; } // note

        [Required(ErrorMessage = "Client should be enabled or disabled")]
        public bool IsDisabled { get; set; }
    }

三个类继承自它:

1)

    public class PrivatePerson : Client // дядя Вася
    {
        public string PrivatePersonSurname { get; set; }
    }

2)

    public class Firm : Client
    {
        [Required(ErrorMessage = "Ownership is required for Firm")]
        public virtual Ownership Ownership { get; set; }

        [Required(ErrorMessage = "Client address is required for Firm")]
        public virtual ClientAddress FirmAddress { get; set; }
    }

3)

    public class AdvertisingAgency : Client
    {
        [Required(ErrorMessage = "Ownership is required for Advertising agency")]
        public virtual Ownership Ownership { get; set; }

        [Required(ErrorMessage = "Client address is required for Advertising agency")]
        public virtual ClientAddress AdvertisingAgencyAddress { get; set; }
    }

!! Firm 和 AdvertisingAgency 的领域相似

这里是 ClientAddress 类:

    public class ClientAddress
    {
        public int ClientAddressId { get; set; }

        [Required(ErrorMessage = "Postal code is required for Client Address")]
        public int PostalCode { get; set; }

        [Required(ErrorMessage = "City is required for Client Address")]
        public virtual City ClientCity { get; set; }

        public int POBox { get; set; }

        public virtual Street ClientStreet { get; set; }

        public string StreetNumber { get; set; }

        public int Appartment { get; set; }

        public string ClientAddressComment { get; set; }
    }

上下文:

public virtual DbSet<Client> Clients { get; set; }
public virtual DbSet<ClientAddress> ClientAddresses { get; set; }

好吧,当我尝试创建数据库时,我得到了这个异常:

System.Data.SqlClient.SqlException H结果=0x80131904 消息=在表 'Clients' 上引入 FOREIGN KEY 约束 'FK_dbo.Clients_dbo.ClientAddresses_FirmAddress_ClientAddressId' 可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。 无法创建约束或索引。查看以前的错误。

谁能指出我的错误? 谢谢

这是我的上下文(部分):

public class FivePlusDBContext : DbContext
{
    public FivePlusDBContext() : base("name = FivePlus")
    {
    }

    public virtual DbSet<City> Cities { get; set; }
    public virtual DbSet<Street> Streets { get; set; }

    public virtual DbSet<Client> Clients { get; set; }
    public virtual DbSet<ClientAddress> ClientAddresses { get; set; }

    public virtual DbSet<Ownership> Ownerships { get; set; }
}

要创建记录,我执行以下操作:

    using (var ctx = new FivePlusDBContext())
        {
            City C_1 = new City() { CityName = "Name" };
            ctx.Cities.Add(C_1);
            ctx.SaveChanges();
        }

【问题讨论】:

  • 你也愿意分享 Fluent Api 代码吗?
  • onModelCreating 方法在 yoru 上下文中看起来如何?您可以尝试以下方法:protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity&lt;Client&gt;() .HasOne(c =&gt; c.ClientAddress) .WithOptional(a =&gt; a.Client) .WillCascadeOnDelete(false); }
  • 编辑了我的问题以帮助您了解我如何创建数据库。当我尝试创建任何记录时,我得到一个异常
  • 我没有使用 DbModelBuilder
  • 不,每个单位(公司或广告代理)都有唯一的地址。

标签: c# entity-framework


【解决方案1】:

首先请注意,EntityFramework 默认情况下每个层次结构只创建一个表(有关详细信息,请参阅here)。在这种情况下,Clients 表中会添加一个特殊列 (Discriminator),以区分持久类。

现在回答你的问题。

根据您的模型,我假设您希望对 FirmAdvertisingAgency 类型的多个客户端使用相同的 ClientAddress。由于FirmAdvertisingAgency 两个类都有ClientAddress 类型的属性,EntityFramework 将在客户端表上生成两个指向ClientAddress 的外键(FK_dbo.Clients_dbo.ClientAddresses_AdvertisingAgencyAddress_ClientAddressIdFK_dbo.Clients_dbo.ClientAddresses_FirmAddress_ClientAddressId)。对于两个外键,EntityFramework 默认启用级联删除。这会导致可能导致多个级联路径的异常。

有多种可能性可以解决问题。

  • 创建两种不同的地址类型,并在Firm 中引用其中一种,在AdvertisingAgency 类中引用另一种(不再可能重复使用地址)
  • 将策略更改为Table per Concrete class (TPC)(请参阅here 也可能解决问题(未测试)
  • 使用 Fluent API 禁用级联删除

要禁用级联删除,请将以下代码添加到您的 Context 类中。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<Firm>()
        .HasRequired(c => c.FirmAddress)
        .WithMany()
        .WillCascadeOnDelete(false);

    modelBuilder.Entity<AdvertisingAgency>()
        .HasRequired(c => c.AdvertisingAgencyAddress)
        .WithMany()
        .WillCascadeOnDelete(false);
}

提及:这可能会导致孤立地址。删除客户端时,其地址不会被删除。但是,该地址仍可能与另一个客户相关。此外,只要地址与至少一个客户相关,就不可能删除地址。如果尝试删除仍与多个客户端相关的地址,则会引发以下异常。

保存不为其关系公开外键属性的实体时发生错误。 EntityEntries 属性将返回 null,因为无法将单个实体标识为异常源。通过在实体类型中公开外键属性,可以更轻松地在保存时处理异常。有关详细信息,请参阅 InnerException。

【讨论】:

  • 非常感谢,伙计。这是我期望听到的。这是如此简单明了。但我卡在某个点上,无法识别错误。再次感谢
猜你喜欢
  • 2011-11-13
  • 2014-03-20
  • 1970-01-01
  • 2019-10-05
  • 2018-08-08
  • 2016-08-01
  • 2013-07-23
  • 2016-11-04
  • 2023-03-22
相关资源
最近更新 更多