Inserting a related entity of a related entity not able to populate Foreign Key of Main Parent Entity

1

I am working with Entity Framework Core 3.0 and am having issues with inserting objects into navigation properties and properly maintaining the Parent Foreign Key.

I have 2 Model Classes

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; }
}

So as you can see a "Type" can have one or many "Criterias" and each "Criteria" can have one or many child "Criterias". So "Criteria" has a self-referencing FK.

Here is the FluentApi Configuration Relationship I have for "Criteria"

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);

So I implemented a UnitOfWork/Repository pattern and have a service layer which uses that. My Service layer for inserting an "EntityType" along with one to many "Criterias" is as follows -

  • Please note that this is a service layer and the caller is passing in an "EntityTypeDTO" object which contains a List of "Criteria" objects and I also have logic to create a List of "children" which is not shown here.

// 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();

So after it tried to Save I get the following exception: 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

So I know where the issue is occuring, but do not know why. EF cannot seem to resolve the TypeId when looping through the children of the Criteria and adding to the criteria.Criterias collection. For the time being I have been using the following workaround -

Instead of adding the child criteria object to the list of "Criterias" like so

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

I have to manually set the EntityType object like this (but I shouldn't have to do it this way):

foreach (CriteriaDTO childDTO in children)
{
         criteria.Criterias.Add(new ModelCriteria
         {
             Name = childDTO.Name,
             EntityType = type
         });
}
c#
entity-framework-core
asked on Stack Overflow Nov 12, 2019 by BryMan • edited Nov 14, 2019 by Erik Philips

1 Answer

1

For the Criteria objects that sit under EntityType there is the one-to-many mapping, so EF can correctly set the TypeId property. But for the child Criteria objects there is no way to tell EF from where to get the value for the TypeId property, so it remind 0 (and thus the FK constraint exception).

I Don't think there is any way around this issue other than the one you demonstrated, except maybe to allow null values in the TypeId property and in the column in the database.

answered on Stack Overflow Nov 14, 2019 by Shahafo

User contributions licensed under CC BY-SA 3.0