Home > Back-end >  Unable to save changes because a circular dependency was detected in the data to be saved
Unable to save changes because a circular dependency was detected in the data to be saved

Time:12-17

I have an entity Transport which can have multiple TransportSteps. At first I used a collection for the relation. But for reasons of performance I wanted to add direct navigation properties and relations from the Transport to specific TransportSteps. Everything works fine, the querying is fast and works properly. But as soon as I'm tryingt save a Transport with a List of TransportSteps and setting the specific relations (PickUpTransportStepId) I'm getting the following exception:

System.InvalidOperationException: Unable to save changes because a circular dependency was detected in the data to be saved: 'Transport [Added] <- TransportSteps Transport { 'TransportId' } TransportStep [Added] <- ArrivalTransportStep { 'ArrivalTransportStepId' } Transport [Added]

Does anyone know how I can keep both relations (List and class) without getting this circular depency? In my opinion it is not really a circular dependency because both relations should be independent.

Entities and configuration:

public class Transport
{
    public ICollection<TransportStep> TransportSteps { get; set; } = new List<TransportStep>();

    public Guid? PickUpTransportStepId { get; set; }

    public TransportStep? PickUpTransportStep { get; set; }

    public Guid? ArrivalTransportStepId { get; set; }

    public TransportStep? ArrivalTransportStep { get; set; }
}

public class TransportStep
{
    public Guid Id { get; set; }

    public Guid TransportId { get; set; }

    public Transport Transport { get; set; }
}

public class TransportConfiguration : IEntityTypeConfiguration<Transport>
{
    public void Configure(EntityTypeBuilder<Transport> builder)
    {
        builder.HasOne(transport => transport.PickUpTransportStep)
            .WithOne()
            .HasForeignKey<Transport>(transport => transport.PickUpTransportStepId)
            .OnDelete(DeleteBehavior.Restrict);

        builder.HasOne(transportStep => transportStep.ArrivalTransportStep)
            .WithOne()
            .HasForeignKey<Transport>(transport => transport.ArrivalTransportStepId)
            .OnDelete(DeleteBehavior.Restrict);
    }
}

public class TransportStepConfiguration : IEntityTypeConfiguration<TransportStep>
{
    public void Configure(EntityTypeBuilder<TransportStep> builder)
    {
        builder.HasOne(transportStep => transportStep.Transport)
            .WithMany(transport => transport.TransportSteps)
            .HasPrincipalKey(transport => transport.Id)
            .HasForeignKey(transportStep => transportStep.TransportId)
            .OnDelete(DeleteBehavior.ClientCascade);
    }
}

Code that throws the exception:

var transportStep1 = new TransportStep();
var transportStep2 = new TransportStep();

var transport = new Transport();
transport.ArrivalTransportStep = transportStep1;
transport.PickUpTransportStep = transportStep2;
transport.TransportSteps.Add(transportStep1);
transport.TransportSteps.Add(transportStep2);

dbContext.Transports.Add(transport);
dbContext.SaveChanges();

CodePudding user response:

I removed the relationship on the TransportStep Entity. Unfortunately EF Core doesn't seem to be able to handle this.

public class Transport
{
    public Guid? PickUpTransportStepId { get; set; }

    public TransportStep? PickUpTransportStep { get; set; }

    public Guid? ArrivalTransportStepId { get; set; }

    public TransportStep? ArrivalTransportStep { get; set; }
}

public class TransportStep
{
    public Guid Id { get; set; }
}

public class TransportConfiguration : IEntityTypeConfiguration<Transport>
{
    public void Configure(EntityTypeBuilder<Transport> builder)
    {
        builder.HasOne(transport => transport.PickUpTransportStep)
            .WithOne()
            .HasForeignKey<Transport>(transport => transport.PickUpTransportStepId)
            .OnDelete(DeleteBehavior.Restrict);

        builder.HasOne(transportStep => transportStep.ArrivalTransportStep)
            .WithOne()
            .HasForeignKey<Transport>(transport => transport.ArrivalTransportStepId)
            .OnDelete(DeleteBehavior.Restrict);
    }
}

public class TransportStepConfiguration : IEntityTypeConfiguration<TransportStep>
{
    public void Configure(EntityTypeBuilder<TransportStep> builder)
    {
    }
}

var transportStep1 = new TransportStep();
var transportStep2 = new TransportStep();

var transport = new Transport();
transport.ArrivalTransportStep = transportStep1;
transport.PickUpTransportStep = transportStep2;

dbContext.SaveChanges();

CodePudding user response:

I think you have a few issues here.

  1. Both transportStep1 and transportStep2 have the same GUID. Because you are newing them up and not setting the Id, they have the default GUID value, which is all zeroes (remember System.Guid is a struct).
  2. The second thing is, and I am not 100% sure of this, is that you may need to attribute the steps in the Transport entity with InversePropertyAttribute.

Again, not sure about #2. On another question I answered years ago, that helped solve their problem. Hopefully #1, #2, or both help you.

  • Related