Один к одному ко многим вызывает циклы или ошибку нескольких каскадных путей - PullRequest
0 голосов
/ 05 февраля 2020

Я использую Entity Framework Core 3.1.0 вместе с SQL Сервером Express во время разработки.

У меня есть отношение один-к-одному и отношение один-ко-многим, связанное так:

Relation --> SupplierSettings --< Conditions

Так что между Relation и SupplierSetting у меня отношение один к одному. Между SupplierSetting и Conditions у меня есть отношение один ко многим.

Выдержки из классов похожи на это.

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] ДОБАВИТЬ CONSTRAINT [FK_SupplierConditions_SupplierImportSettings_SupplierImportSettingId] FOREIGN KEY ([SupplierImportSettingId]) СВЯЗАТЬСЯ [SupplierImportSettingId] (Поставщик): 023 * *. ограничение 'FK_SupplierConditions_SupplierImportSettings_SupplierImportSettingId' в таблице 'SupplierConditions' может вызывать циклы или несколько каскадных путей. Укажите 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<br> 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
в Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning (TdsParserStateObject stateObj, булевская функция-оператор \ вкл. \ src \ Microsoft.Data.SqlClient \ netcore \ src \ Microsoft \ Data \ SqlClient \ TdsParser.cs: строка 1169
в Microsoft.Data.SqlClient.TdsParser.TryRun (RunBehavior, runBehavior, SqlCopy, SqlDellSourceShellSlayer, SqlDellSourceShellShellResslerShellResslerShellRessboardShellResslerShellShellResslerShellShellRD) , TdsParserStateObject stateObj, Boolean & dataReady) в E: \ agent1_work \ 34 \ s \ src \ Microsoft.Data.SqlClient \ netcore \ src \ Microsoft \ Data \ SqlClient \ TdsParser.cs: строка 1719
в Microsoft.Data.Sqlli .SqlCommand.RunExecuteNonQueryTds (String methodName, логическое значение isAsyn c, время Int32 out, Boolean asyncWrite) в E: \ agent1_work \ 34 \ s \ src \ Microsoft.Data.SqlClient \ netcore \ src \ Microsoft \ Data \ SqlClient \ 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<br> 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<br> at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)<br> at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary 2 parameterValues)
в Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery (IEnumerable`1igrationCommands, соединение IRelationalConnection (). String targetMigration)
в Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase (String targetMigration, String contextType)
в Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl (String targetTypepe Microsoft) .EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase. <> C__DisplayClass0_0. <. Ctor> b__0 ()
в Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute (действие))

ClientConnectionId: 3563e9af-ca34-45d c -a3aa-76394f5cfcbd
Номер ошибки: 1785, состояние: 0, класс: 16
Введение ограничения FOREIGN KEY 'FK_SupplierConditions_SupplierImportSipport' циклы или несколько каскадных путей. Укажите ON DELETE NO ACTION или ON UPDATE NO ACTION или измените другие ограничения FOREIGN KEY. Не удалось создать ограничение или индекс. См. Предыдущие ошибки.

На самом деле, SQL Сервер, вероятно, прав, потому что, когда я удаляю сущность 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 ]

2 голосов
/ 05 февраля 2020

Я вижу, что то, как вы настроили отношения, приведет к удалению условий при удалении настройки поставщика. Это приведет к удалению других настроек поставщика, что неправильно. Вероятно, это и есть причина его сбоя.

// Попробуйте это изменение

modelBuilder.Entity<SupplierImportSetting>()
    .HasMany(sis => sis.Conditions)
    .WithOne(c => c.SupplierImportSetting)
    .HasForeignKey(c => c.SupplierImportSettingId)
    .OnDelete(DeleteBehavior.NoAction);
0 голосов
/ 06 февраля 2020

После многих часов отладки мы наконец нашли ответ.

Хотя Relation, SupplierImportSetting и SupplierCondition не показывали первичный ключ для еще одной задействованной таблицы, оказалось, что есть еще одна таблица, которую я забыл около. Действительно раздражает, что MS SQL может обнаруживать наличие нескольких каскадных путей, но не сообщает нам , какой путь конфликтует.

Это то, как мы наконец выяснили. Находясь в SQL Management Studio, раскройте таблицу, из которой исходит ошибка. В моем случае это было условие поставщика. Затем откройте папку «Ключи». Затем дважды щелкните значок ключа перед внешним ключом. Откроется новое всплывающее окно с отношениями внешних ключей. Это окно не только показывает внешние ключи для других таблиц, но также показывает внешние ключи от других таблиц к этой.

enter image description here

Поэтому я добавил a DeleteBehaviour NoAction по этому отношению, а затем проблема исчезла. У меня все еще было удаление каскада, как я и планировал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...