.Net Entity Framework介绍FOREIGN KEY约束异常

时间:2017-12-20 12:57:33

标签: c# entity-framework

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

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

从中继承了三个类:

1)

    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; }
    }

2)

    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; }
    }

3)

    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; }
    }

!!公司和AdvertisingAgency有类似的领域

这是ClientAddress类:

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

上下文:

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; }
}

好吧,当我试图创建一个数据库时,我得到了这个例外:

  

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

请有人指出我的错误吗? 感谢

这是我的背景(部分):

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

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

{{1}}

1 个答案:

答案 0 :(得分:0)

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

现在回答你的问题。

根据您的模型,我假设您希望对ClientAddressFirm类型的多个客户使用相同的AdvertisingAgency。由于类FirmAdvertisingAgency都具有ClientAddress类型的属性,因此EntityFramework将在Clients表上生成两个外键,指向ClientAddressFK_dbo.Clients_dbo.ClientAddresses_AdvertisingAgencyAddress_ClientAddressId和{{ 1}})。对于这两个外键,EntityFramework默认启用级联删除。这导致例外,这可能导致多个级联路径。

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

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

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

Table per Concrete class (TPC)

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

  

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