'Entity Framework circular dependency for last entity

Please consider the following entities

public class What {
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Track> Tracks { get; set; }
    public int? LastTrackId { get; set; }]
    public Track LastTrack { get; set; }
}

public class Track {
    public Track(string what, DateTime dt, TrackThatGeoposition pos) {
        What = new What { Name = what, LastTrack = this };
    }

    public int Id { get; set; }

    public int WhatId { get; set; }
    public What What { get; set; }
}

I use the following to configure the entities:

builder.HasKey(x => x.Id);
builder.HasMany(x => x.Tracks).
    WithOne(y => y.What).HasForeignKey(y => y.WhatId);
builder.Property(x => x.Name).HasMaxLength(100);
builder.HasOne(x => x.LastTrack).
    WithMany().HasForeignKey(x => x.LastTrackId);

Has you can see there is a wanted circular reference:

What.LastTrack <-> Track.What

when I try to add a Track to the context (on SaveChanges in fact):

Track t = new Track("truc", Datetime.Now, pos);
ctx.Tracks.Add(t);
ctx.SaveChanges();

I get the following error:

Unable to save changes because a circular dependency was detected in the data to be saved: ''What' {'LastTrackId'} -> 'Track' {'Id'}, 'Track' {'WhatId'} -> 'What' {'Id'}'.

I would like to say... yes, I know but...

Is such a configuration doable with EF Core ?



Solution 1:[1]

I encountered the same problem, but i solved it differently.

In my case, it was about a list of status and a reference to the last status. So with the following case :

public class What {
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Status> StatusList { get; set; }
    public int? LastStatusId { get; set; }
    public Status LastStatus { get; set; }

    public void AddStatus(Status s)
    {
        StatusList.Add(s);
        LastStatus = s;
    }
}

public class Status{
    public int Id { get; set; }

    public int WhatId { get; set; }
    public What What { get; set; }
}

In my program, i changed my code to use StatusList as an history that doesn't include the lastStatus, so :

public class What {
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Status> StatusHistory { get; set; }
    public int? LastStatusId { get; set; }
    public Status LastStatus { get; set; }

    public void AddStatus(Status s)
    {
        if(LastStatus) StatusList.Add(LastStatus);
        LastStatus = s;
    }

    public List<Status> GetStatusList(Status s) // If needed, a method, not a property because i got an error with lazyLoading
    {
        return new List<Status>(StatusHistory) { LastStatus}; // List of all status (history + last)
    }
}

public class Status{
    public int Id { get; set; }

    public int? WhatId { get; set; }
    public What What { get; set; }
}

and don't forget to put in your context IsRequired(false) on the foreignKey :

builder.HasMany(x => x.Status).
    WithOne(y => y.What).HasForeignKey(y => y.WhatId).IsRequired(false);

Like this, no more circular reference.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 novaXire