EF Migrations DropForeignKey fails when key is in a base class

坚强是说给别人听的谎言 提交于 2019-12-23 09:34:34

问题


I'm attempting to update my data models for an EF 5.0.0-rc code-first class library. The first command in the Up() method is

DropForeignKey("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" }, "dbo.ChileProducts");

but I'm getting a SqlException: 'FK_dbo.ChileInventory_dbo.ChileProducts_LotInventoryItemTypeId_ChileProductId' is not a constraint. Could not drop constraint.

I think that the cause for the error is due to the fact that my ChileProducts class get's it's key properties from its base class. Since there is no overload of the DropForeignkey method which accepts the principal column name(s), I believe EF is unable to determine the correct constraint to drop. I should also point out that the constraint name displayed in the exception message does not match up with the constraint name in the database (hence the error...)

Below you'll find the data models and the migration methods. But first a quick note about the nature of the change behind the migration: Each derivative of the InventoryBase class defines product type through the composite key of InventoryTypeId and [InventoryTypeSpecific]ProductId. For example, ChileInventory would identify it's particular chile type type as InventoryItemTypeId = [ChileInventoryTypeId] and ChileProductId = [ChileProductId]. PackagingInventory would identify it's packaging type as InventoryItemTypeId = [PackagingInventoryTypeId] and PackagingProductId = [PackagingProductId]. And so on.

The model change I'm working to roll out is the elevation of the [InventoryTypeSpecific]ProductId from each InventoryBase derivative into the base. This would result in all InventoryBase derived objects sharing a common ProductId property which, in conjunction with the InventoryItemTypeId, would enable navigation from InventoryBase to ProductBase; which isn't possible in the previous model.

Thanks, in advance for your advice and consideration. --Vinney

Data Models

Chile Product

public abstract class ProductBase
{
    [Key]
    [Column(Order = 0)]
    public virtual int InventoryItemTypeId { get; set; }

    [Key]
    [Column(Order = 1)]
    public virtual int Id { get; set; }

    [StringLength(150)]
    public virtual string Name { get; set; }

    [ForeignKey("InventoryItemTypeId")]
    public virtual InventoryItemType InventoryItemType { get; set; }

    public virtual bool IsActive { get; set; }
}
public class ChileProduct : ProductBase
{
    public virtual int ChileTypeId { get; set; }

    [ForeignKey("ChileTypeId")]
    public virtual ChileType ChileType { get; set; }
}

Chile Inventory

public abstract class InventoryBase
{
    [Key]
    [Column(Order = 0, TypeName = "Date")]
    public virtual DateTime DateCreated { get; set; }

    [Key]
    [Column(Order = 1)]
    public virtual int Sequence { get; set; }

    [Key]
    [Column(Order = 2)]
    public virtual int LotInventoryItemTypeId { get; set; }

    [Column(TypeName = "Date")]
    public virtual DateTime LotDateCreated { get; set; }

    public virtual int LotSequence { get; set; }

    public virtual int ProductId { get; set; }

    [ForeignKey("LotInventoryItemTypeId, LotDateCreated, LotSequence")]
    public virtual Lot Lot { get; set; }

    [ForeignKey("LotInventoryItemTypeId")]
    public virtual InventoryItemType ItemType { get; set; }

    public virtual ICollection<InventoryQuantityByLocation> QuantitiesByLocation { get; set; }

    [ForeignKey("LotInventoryItemTypeId, ProductId")]
    public virtual ProductBase ProductBase { get; set; }
}

public class ChileInventory : InventoryBase
{
    [Column(TypeName = "Date")]
    public virtual DateTime? ProductionBatchDateCreated { get; set; }

    public virtual int? ProductionBatchSequence { get; set; }

    public virtual int PackagingInventoryItemTypeId { get; set; }

    public virtual int PackagingProductId { get; set; }

    [ForeignKey("ProductionBatchDateCreated, ProductionBatchSequence")]
    public virtual ProductionBatch ProductionBatch { get; set; }

    [ForeignKey("LotInventoryItemTypeId, ProductId")]
    public virtual ChileProduct ChileProduct { get; set; }

    [ForeignKey("PackagingInventoryItemTypeId, PackagingProductId")]
    public virtual PackagingProduct PackagingProduct { get; set; }

}

Migration

public override void Up()
    {
        DropForeignKey("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" }, "dbo.ChileProducts");
        DropForeignKey("dbo.PackagingInventory", new[] { "LotInventoryItemTypeId", "PackageId" }, "dbo.PackagingProducts");
        DropForeignKey("dbo.AdditiveInventory", new[] { "LotInventoryItemTypeId", "AdditiveProductId" }, "dbo.AdditiveProducts");
        DropIndex("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" });
        DropIndex("dbo.PackagingInventory", new[] { "LotInventoryItemTypeId", "PackageId" });
        DropIndex("dbo.AdditiveInventory", new[] { "LotInventoryItemTypeId", "AdditiveProductId" });
        AddColumn("dbo.Inventory", "ProductId", c => c.Int(nullable: false));
        AddForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
        AddForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
        AddForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
        AddForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
        CreateIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
        CreateIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
        CreateIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
        CreateIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
        DropColumn("dbo.ChileInventory", "ChileProductId");
        DropColumn("dbo.PackagingInventory", "PackageId");
        DropColumn("dbo.AdditiveInventory", "AdditiveProductId");
    }

    public override void Down()
    {
        AddColumn("dbo.AdditiveInventory", "AdditiveProductId", c => c.Int(nullable: false));
        AddColumn("dbo.PackagingInventory", "PackageId", c => c.Int(nullable: false));
        AddColumn("dbo.ChileInventory", "ChileProductId", c => c.Int(nullable: false));
        DropIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
        DropIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
        DropIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
        DropIndex("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" });
        DropForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts");
        DropForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts");
        DropForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts");
        DropForeignKey("dbo.Inventory", new[] { "LotInventoryItemTypeId", "ProductId" }, "dbo.AdditiveProducts");
        DropColumn("dbo.Inventory", "ProductId");
        CreateIndex("dbo.AdditiveInventory", new[] { "LotInventoryItemTypeId", "AdditiveProductId" });
        CreateIndex("dbo.PackagingInventory", new[] { "LotInventoryItemTypeId", "PackageId" });
        CreateIndex("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" });
        AddForeignKey("dbo.AdditiveInventory", new[] { "LotInventoryItemTypeId", "AdditiveProductId" }, "dbo.AdditiveProducts", new[] { "InventoryItemTypeId", "Id" });
        AddForeignKey("dbo.PackagingInventory", new[] { "LotInventoryItemTypeId", "PackageId" }, "dbo.PackagingProducts", new[] { "InventoryItemTypeId", "Id" });
        AddForeignKey("dbo.ChileInventory", new[] { "LotInventoryItemTypeId", "ChileProductId" }, "dbo.ChileProducts", new[] { "InventoryItemTypeId", "Id" });
    }

回答1:


If your initial model was created with the EF 4.3 then you will have such errors in EF 5.0 since the rules for generating PK/FK constraint names have changed between these two versions of the EF.

See this question for details and another possible solution.




回答2:


Here's one work around I found:

Use the DropForeignKey overload which contains the parameters principalName and name -- which in this case means constraint name! It's a little more fragile becuase it requires the knowledge of the constraint name upfront but it works as expected.



来源:https://stackoverflow.com/questions/11528476/ef-migrations-dropforeignkey-fails-when-key-is-in-a-base-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!