4

我的代码优先数据库运行良好。如果我对我的数据库上下文进行了更改,那么下次我启动应用程序时数据库将被更新。但是后来我在数据库中添加了一些模型,当我重新启动我的应用程序时出现了这个错误:

Introducing FOREIGN KEY constraint 'FK_OrderDetails_Orders_OrderId' on table 'OrderDetails' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors.

奇怪的事情之一是,如果我在不更改任何内容的情况下再次启动应用程序,则会收到以下错误:

Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations.

为了让第一个错误再次发生,我必须删除我的 .mdf 和 .ldf 文件(数据库),并用我的修订历史记录中的副本仅替换 .mdf 文件。

为什么会发生这种情况?


以供参考:

我的 Global.asax.cs 文件在Application_Start()方法中有这个:

Database.SetInitializer<EfDbContext>(new EfDbContextInitializer());

看起来像这样:

public class EfDbContextInitializer : DropCreateDatabaseIfModelChanges<EfDbContext>
{
    protected override void Seed(EfDbContext context)
    {
        var orders = new List<Order>
            {
                . . .
            };
        orders.ForEach(s => context.Orders.Add(s));
         . . . etc. . .
        context.SaveChanges();
    }
}

我的连接字符串来自Web.config

<add name="EFDbContext" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;database=pos;AttachDBFilename=|DataDirectory|pos.mdf;MultipleActiveResultSets=true;User Instance=true" providerName="System.Data.SqlClient" />

最后,我的 Order 和 OrderDetails 模型(第一个错误是直接引用的):

public class Order
{
    public int OrderId { get; set; }

    public List<OrderDetail> OrderDetails { get; set; }

    public int EstablishmentId { get; set; }

    public virtual Establishment Establishment { get; set; }
}

public class OrderDetail
{
    public int OrderDetailId { get; set; }

    public int OrderId { get; set; }

    public int ProductId { get; set; }

    public int Quantity { get; set; }

    public decimal UnitPrice { get; set; }

    public virtual Product Product { get; set; }

    public virtual Order Order { get; set; }
}

更新/注意:如果我在 OrderDetail 类中注释掉public int OrderId { get; set; },项目启动正常(尽管我没有获得所需的添加OrderId(当然)的能力。

4

3 回答 3

11

此问题是由可能的循环级联删除引起的。这可能以多种形式发生,但归结为一条记录同时被两个或多个级联删除规则删除。

例如,假设您有父表和两个子表。然后你还有另一个表链接到两个子表:

Parent
------
ParentId
Name

ChildOne
--------
ChildOneId
ParentId
Name

ChildTwo
--------
ChildTwoId
ParentId
Name

SharedChild
-----------
SharedChildId
ChildOneId
ChildTwoId
Name

当您从 Parent 表中删除一条记录时,此删除可能会级联到 ChildOneChildTwo。然后这两个删除可以进一步级联到 SharedChild,这里我们遇到了问题:两条路径试图从 SharedChild 中删除相同的记录。

我并不是说你的情况完全一样,但无论如何,你有类似的事情发生。为了解决这个问题,您可以决定让一个分支在链中向下级联,并阻止它在另一条链中。

仅在第一次运行应用程序时以及每次删除数据库时都出现此错误的原因是(我相信)Entity Framework 在发生错误时停止生成数据库并且您留下的数据库不完整。这就是为什么您在其他情况下遇到其他错误的原因。

如果您需要更多帮助来解决循环级联删除,您可能需要显示整个数据模型及其关系。

于 2012-08-08T14:03:03.817 回答
2

要解决此问题,您需要做的是删除外键属性,并将引用的对象保留为虚拟:

这就是我所做的:

当我有这个错误时的旧代码:

    public class OperatingSystemType
{
    public int OperatingSystemTypeID { get; set; }

    [StringLength(50)]
    [Required]
    public string OperatingSystemName { get; set; }

    public int CompanyID { get; set; }

    [ForeignKey("CompanyID")]
    public virtual Company Company { get; set; }
}

解决此错误后的新代码:

    public class OperatingSystemType
{
    public int OperatingSystemTypeID { get; set; }

    [StringLength(50)]
    [Required]
    public string OperatingSystemName { get; set; }

    public virtual Company Company { get; set; }
}

然后在种子中,添加如下所示的数据,因为我们只是将 Company 对象添加为 OperatingSystemType 的参数值之一:

        protected override void Seed(MyAPPMVC.Infrastructure.MyContext context)
    {
        string myusername = "myuser";
        string MicrosoftName = "Microsoft";

        context.Companies.AddOrUpdate(p => p.CompanyName,
            new Company { CompanyName = MicrosoftName, CreatedOn = DateTime.Now, CreatedBy = myusername }
            );

        context.SaveChanges();

        Company MicrosoftCompany = context.Companies.Where(p => p.CompanyName == MicrosoftName).SingleOrDefault();

        context.OperationgSystemTypes.AddOrUpdate(p => p.OperatingSystemName,
            new OperatingSystemType { OperatingSystemName = "Windows 7 Professional", Company = MicrosoftCompany, CreatedOn = DateTime.Now, CreatedBy = myusername },
            new OperatingSystemType { OperatingSystemName = "Windows 8 Professional", Company = MicrosoftCompany, CreatedOn = DateTime.Now, CreatedBy = myusername }
            );
于 2013-05-13T23:47:19.723 回答
2

我用 OnModelCreating 中的这段代码解决了 EF Core 上的这个问题:

foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
{
    relationship.DeleteBehavior = DeleteBehavior.Restrict;
}
于 2021-06-10T08:54:01.517 回答