Циклическая зависимость Entity Framework для последней сущности

пожалуйста, рассмотрите следующие объекты

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

Я использую следующее Для настройки сущностей:

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

вы можете видеть, что есть разыскиваемая круговая ссылка:

What.LastTrack <-> Track.What

когда я пытаюсь добавить Track к контексту (on SaveChanges на самом деле):

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

Я получаю следующую ошибку:

не удалось сохранить изменения, поскольку в сохраняемых данных была обнаружена циклическая зависимость: "What' {'LastTrackId'} - >'Track' {'Id'}, 'Track' {'WhatId'} - > 'What' {'Id'}'.

Я хотел сказать... да, я знаю, но...

такая конфигурация выполнима с ядром EF ?

1 ответов


это то, что я называю любимый ребенок проблема: родитель имеет несколько детей, но один из них является особенным. Это вызывает проблемы в реальной жизни... и в обработке данных.

в вашей модели класса What (кстати, это разумное имя?) имеет Tracks как дети, но один из них LastTrack является особым ребенком, которому What сохраняет ссылку.

когда как What и Tracks создаются в одной транзакции, EF будет попробуйте использовать сгенерированный What.Id вставить новый TrackС WhatId. Но прежде чем он сможет спасти What ему нужен сгенерированный идентификатор последнего Track. Поскольку базы данных SQL не могут вставлять записи одновременно, эта циклическая ссылка не может быть установлена в одной изолированной транзакции.

вам нужна одна транзакция для сохранения What и Tracks и последующая транзакция для установки What.LastTrackId.

для этого в одной транскрипции базы данных вы можете обернуть код в TransactionScope:

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

если исключение происходит, ts.Complete(); не произойдет, и откат произойдет, когда TransactionScope удален.