Вставка связанного объекта связанного объекта, который не может заполнить внешний ключ основного родительского объекта - PullRequest
1 голос
/ 12 ноября 2019

Я работаю с Entity Framework Core 3.0 и у меня возникают проблемы с вставкой объектов в свойства навигации и должным образом поддерживающим Родительский внешний ключ.

У меня есть 2 класса моделей

EntityType.cs

public class EntityType
{
   public int TypeId { get; set; }
   public string Name { get; set; }

   public virtual ICollection<Criteria> Criterias { get; set; }
}

Criteria.cs

public class Criteria
{
   public int CriteriaId { get; set; }
   public int TypeId { get; set; }
   public int? ParentCriteriaId { get; set; }
   public string Name { get; set; }

   public virtual EntityType Type { get; set; }
   public virtual Criteria ParentCriteria { get; set; }

   public virtual ICollection<Criteria> Criterias { get; set; }
}

Таким образом, как вы можете видеть, «Тип» может иметь один или несколько «Критериев» икаждый «критерий» может иметь один или несколько дочерних «критериев». Таким образом, «Критерии» имеют FK с самоссылкой.

Вот отношение конфигурации FluentApi, которое у меня есть для «Критерии»

builder.HasOne(x => x.Type).WithMany(x => x.Criterias).HasForeignKey(x => x.TypeId).OnDelete(DeleteBehavior.Restrict);
builder.HasOne(x => x.ParentCriteria).WithMany(x => x.Criterias).HasForeignKey(x => x.ParentCriteriaId).OnDelete(DeleteBehavior.Restrict);

Итак, я реализовал шаблон UnitOfWork / Repository и получил сервисслой, который использует это. Мой сервисный слой для вставки «EntityType» вместе с одним или многими «критериями» выглядит следующим образом -

  • Обратите внимание, что это сервисный слой, и вызывающая сторона передает объект «EntityTypeDTO», которыйсодержит список объектов «Критерии», и у меня также есть логика для создания списка «детей», который здесь не показан.

// The main parent object to be created
EntityType type = new EntityType
{
    Name = entityTypeDTO.Name
};

foreach (CriteriaDTO criteriaDTO in entityTypeDTO.Criterias)
{
     // Create the top level Criteria object which will be the "Parent"
     // No problem here, EF is able to populate the TypeId FK for the Parent
     Criteria criteria= new Criteria
     {
         Name = criteriaDTO.Name     
     };

     foreach (CriteriaDTO childDTO in children)
     {
        // Loop through the children of the parent and add to the navigation property
        // Here is where the problem is, EF is able to populate the ParentCriteriaId FK but
        // for some reason cannot resolve the TypeId FK
         criteria.Criterias.Add(new ModelCriteria
         {
             Name = childDTO.Name
         });
     }

     type.Criterias.Add(criteria);
}

UnitOfWork.ModelTypeRepository.Add(type);

await UnitOfWork.SaveAsync();

Поэтому после попытки сохранения я получаю следующее исключение: Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> Microsoft.Data.SqlClient.SqlException (0x80131904): The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Criteria_EntityTypes_TypeId". The conflict occurred in database

Итак, я знаю, где возникает проблема, но не знаю, почему. EF не может разрешить TypeId при циклическом просмотре дочерних элементов Criteria и добавлении в коллекцию критериев.Criterias. В настоящее время я использую следующий обходной путь -

Вместо добавления дочернего объекта критериев в список «Критерии», например, так:

foreach (CriteriaDTO childDTO in children)
{
         criteria.Criterias.Add(new ModelCriteria
         {
             Name = childDTO.Name
         });
}

Я должен вручную установить EntityTypeобъект вроде этого (но я не должен был делать это так):

foreach (CriteriaDTO childDTO in children)
{
         criteria.Criterias.Add(new ModelCriteria
         {
             Name = childDTO.Name,
             EntityType = type
         });
}

1 Ответ

1 голос
/ 14 ноября 2019

Для объектов Criteria, которые находятся в EntityType, существует отображение один-ко-многим, поэтому EF может правильно установить свойство TypeId. Но для дочерних объектов Criteria невозможно указать EF, откуда взять значение для свойства TypeId, поэтому оно напоминает 0 (и, следовательно, исключение ограничения FK).

Я не думаю, что есть какой-либо способ обойти эту проблему, кроме той, которую вы продемонстрировали, за исключением, возможно, разрешения пустых значений в свойстве TypeId и в столбце в базе данных.

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