繁体   English   中英

.Net实体框架引入FOREIGN KEY约束异常

[英].Net Entity Framework Introducing FOREIGN KEY constraint exception

这是我的数据库的一部分,根据代码优先原则创建:我有一个抽象类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; }
    }

!! 公司和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 HResult = 0x80131904消息=在表“客户端”上引入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();
        }

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

现在到您的问题。

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

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

  • 创建两种不同的地址类型,并在Firm引用其中一种,并在AdvertisingAgency类中引用另一种(不再可以重复使用地址)
  • 将策略更改为Table per Concrete class (TPC) (请参见此处也可以解决问题(未测试)
  • 使用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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM