Entity Framework circular dependency for last entity

坚强是说给别人听的谎言 提交于 2020-04-08 09:22:05

问题


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 ?


回答1:


This is what I like to call the favored child problem: a parent has multiple children, but one of them is extra special. This causes problems in real life... and in data processing.

In your class model, What (is that a sensible name, by the way?) has Tracks as children, but one these, LastTrack is the special child to which What keeps a reference.

When both What and Tracks are created in one transaction, EF will try to use the generated What.Id to insert the new Tracks with WhatId. But before it can save What it needs the generated Id of the last Track. Since SQL databases can't insert records simultaneously, this circular reference can't be established in one isolated transaction.

You need one transaction to save What and its Tracks and a subsequent transaction to set What.LastTrackId.

To do this in one database transcation you can wrap the code in a TransactionScope:

using(var ts = new TransactionScope())
{
    // do the stuff
    ts.Complete();
}

If an exception occurs, ts.Complete(); won't happen and a rollback will occur when the TransactionScope is disposed.



来源:https://stackoverflow.com/questions/40073149/entity-framework-circular-dependency-for-last-entity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!