一对多导致循环或多个级联路径错误

时间:2020-02-05 12:42:44

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

在开发过程中,我将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] FOREIGN KEY([SupplierImportSettingId])参考[SupplierImportSettings]([Id])在DELETE CAS

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

在Microsoft:Data.SqlClient.SqlConnection.OnError(SqlException异常,布尔值breakConnection,动作1 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)在E:\ agent1_work \ 34 \ s \ src \ Microsoft.Data.SqlClient \ netcore \ src中\ Microsoft \ 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 \ Microsoft \ Data \ SqlClient \ TdsParser.cs:行1719
在E. \ SqlCommand.cs:行2857
在Microsoft.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource 1 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(String targetMigration,String contextType)
在Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration,String contextType)
在Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase。<> c__DisplayClass0_0。<。ctor> b__0()
在Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(操作动作)处

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是主体,因此应删除其他记录。

所以我想,也许我也需要定义一对一关系的另一种方式。当我将其添加到我的上下文配置中时,迁移运行并执行而没有错误。但是,当我检查数据库时,在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来创建所需的情况。

2 个答案:

答案 0 :(得分:2)

我看到删除了providerSettings时,如何配置关系将导致条件的删除。这将导致其他供应商设置的删除,这是错误的。可能这就是失败的原因。

//尝试更改

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

答案 1 :(得分:0)

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

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

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

enter image description here

因此我在此关系上添加了DeleteBehaviour NoAction,然后问题消失了。我仍然可以按预期进行级联删除。