【问题标题】:One to one to many causes cycles or multiple cascade paths error一对一多导致循环或多级联路径错误
【发布时间】:2020-05-21 09:16:04
【问题描述】:

我在开发过程中将 Entity Framework Core 3.1.0 与 SQL Server Express 一起使用。

我有一个一对一的关系和一个一对多的关系,如下所示:

Relation --> SupplierSettings --< Conditions

所以在RelationSupplierSetting 之间我有一对一的关系。在SupplierSettingConditions 之间,我有一对多的关系。

类的摘录是这样的。

public class Relation
{
    public string GLN { get; set; } 
    public string Name { get; set; }
    public string Country { get; set; } 
}

public class SupplierImportSetting 
{
    public Relation Supplier { get; set; }
    public int SupplierId { get; set; }

    public int MinimumMarginPercentage { get; set; }
    public bool OnlyImportWithConditions { get; set; }

    public ICollection<SupplierCondition> Conditions { get; set; }
}

public class SupplierCondition 
{
    public SupplierImportSetting SupplierImportSetting { get; set; }
    public int SupplierImportSettingId { get; set; }

    public string DiscountGroup { get; set; }
    public string SupplierTradeItemCode { get; set; }
    public string Description { get; set; }

    public decimal? Discount1Percentage { get; set; } // 1 = 100%
}

我这样配置我的上下文:

// One to one where Relation is Principal and SupplierImportSetting is dependent.
modelBuilder.Entity<Relation>()
    .HasOne<SupplierImportSetting>()
    .WithOne(sis => sis.Supplier)
    .HasForeignKey<SupplierImportSetting>(sis => sis.SupplierId)
    .OnDelete(DeleteBehavior.Cascade);

// One to many with SupplierImportSetting as Principal and SupplierCondition as dependent.
modelBuilder.Entity<SupplierImportSetting>()
    .HasMany(sis => sis.Conditions)
    .WithOne(c => c.SupplierImportSetting)
    .HasForeignKey(c => c.SupplierImportSettingId)
    .OnDelete(DeleteBehavior.Cascade);

但我收到此错误:

执行 DbCommand 失败 (11ms) [Parameters=[], CommandType='Text', CommandTimeout='30']

ALTER TABLE [SupplierConditions] 添加约束 [FK_SupplierConditions_SupplierImportSettings_SupplierImportSettingId] 外键 ([SupplierImportSettingId]) 引用 [SupplierImportSettings] ([Id]) ON DELETE CASCADE;

Microsoft.Data.SqlClient.SqlException (0x80131904):在表“SupplierConditions”上引入 FOREIGN KEY 约束“FK_SupplierConditions_SupplierImportSettings_SupplierImportSettingId”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。 无法创建约束或索引。查看以前的错误。

在 E:\agent1_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft 中的 Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException 异常,布尔型 breakConnection,Action1 wrapCloseInAction) in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\SqlConnection.cs:line 1591
at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action
1 wrapCloseInAction) \Data\SqlClient\SqlInternalConnection.cs:第 618 行
在 E:\agent1_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\TdsParser 中的 Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)。 cs:第 1169 行
在 Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) 在 E:\agent1_work\34\s\src\Microsoft.Data.SqlClient\netcore\src \Microsoft\Data\SqlClient\TdsParser.cs:1719 行
在 E:\agent1_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient 中的 Microsoft.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean isAsync, Int32 timeout, Boolean asyncWrite) \SqlCommand.cs:第 2857 行
在 Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource1 completion, Boolean sendToPipe, Int32 timeout, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String methodName) in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\SqlCommand.cs:line 1395
at Microsoft.Data.SqlClient.SqlCommand.ExecuteNonQuery() in E:\agent1\_work\34\s\src\Microsoft.Data.SqlClient\netcore\src\Microsoft\Data\SqlClient\SqlCommand.cs:line 974
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary
2 parameterValues)
在 Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands,IRelationalConnection 连接)
在 Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
在 Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(字符串 targetMigration,字符串 contextType)
在 Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(字符串 targetMigration,字符串 contextType)
在 Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.c__DisplayClass0_0.<.ctor>b__0()
在 Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action 动作)

ClientConnectionId:3563e9af-ca34-45dc-a3aa-76394f5cfcbd
错误号:1785,状态:0,类:16
在表“SupplierConditions”上引入 FOREIGN KEY 约束“FK_SupplierConditions_SupplierImportSettings_SupplierImportSettingId”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。 无法创建约束或索引。查看以前的错误。

其实SQL Server 可能是对的,因为当我删除一个Relation 实体时,这会导致级联级联删除。但这就是我想要的。 Relation是principal,所以应该删除其他记录。

所以我想,也许我还需要定义一对一关系的另一种方式。当我将它添加到我的上下文配置中时,迁移运行并没有错误地执行。但是当我检查数据库时,在 SupplierImportSettings 上创建的约束没有 ON DELETE。因此,当我删除 Relation 实体时,不会删除 SupplierImportSettings。这不是我想要的。

// SupplierImportSetting is principal, Relation is dependent.
// Define one to one the other way to disable cascade delete in this direction.
modelBuilder.Entity<SupplierImportSetting>()
    .HasOne<Relation>(sis => sis.Supplier)
    .WithOne()
    .OnDelete(DeleteBehavior.NoAction);

无论我尝试什么,我都无法让 Entity Framework Core 来创建我想要的情况。

【问题讨论】:

  • 所示模型没有循环/多级联路径。必须有其他未在此处显示的关系导致它。
  • 如果您将此作为答案发布,我本可以接受。我会用更多信息来回答它。

标签: c# .net sql-server entity-framework-core


【解决方案1】:

我看到您配置关系的方式将导致在删除供应商设置时删除条件。这将导致删除其他错误的供应商设置。可能这就是它失败的原因。

// 试试这个改变

modelBuilder.Entity<SupplierImportSetting>()
    .HasMany(sis => sis.Conditions)
    .WithOne(c => c.SupplierImportSetting)
    .HasForeignKey(c => c.SupplierImportSettingId)
    .OnDelete(DeleteBehavior.NoAction);

【讨论】:

    【解决方案2】:

    经过几个小时的调试,我们终于找到了答案。

    虽然 Relation、SupplierImportSetting 和 SupplierCondition 没有显示另一个涉及的表的主键,但事实证明我忘记了另一个表。真的很烦人,MS SQL 能够检测到存在多个级联路径,但没有告诉我们哪个路径有冲突。

    这就是我们最终发现的方式。在 SQL Management Studio 中,展开错误所在的表。就我而言,这是供应商条件。然后打开密钥“文件夹”。然后双击外键前面的键图标。这将打开一个带有外键关系的新弹出窗口。此窗口不仅显示其他表的外键,还显示其他表的外键。

    所以我在这个关系上添加了一个 DeleteBehaviour NoAction,然后问题就消失了。我仍然按预期进行了级联删除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-10
      • 2018-08-10
      • 2013-11-16
      • 2016-03-26
      • 2019-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多