Выявление циклической зависимости при сохранении объектов в EF Core - PullRequest
0 голосов
/ 02 октября 2018

У меня есть таблица с именем Record, и у каждого Record есть коллекция файлов изображений с именем RecordImage.Таблица RecordImage имеет флаг IsMainImage, указывающий, какое из изображений Record является основным.Может быть только один IsMainImage для каждого Record.

public class Record
{
    public Guid RecordId { get; set; }
    public ICollection<RecordImage> RecordImage { get; set; }
}

public class RecordImage
{
    public Guid RecordImageId { get; set; }
    public Guid RecordId { get; set; }
    public byte[] ImageData { get; set; }
    public bool IsMainImage { get; set; }

    public virtual Record Record { get; set; }
}

Я использую загрузчик файлов ajax для обновления RecordImages, пользователи нажимают на флажок, чтобы отметить основное изображение и связанный с ним RecordImage обновляется на сервере.Когда я делаю это, я должен проверить существующий IsMainImage и установить его в ложное значение в пользу нового:

[HttpPut]
public async Task<IActionResult> Put(Guid key, string values)
{
RecordImage image = await _context.RecordImage.FindAsync(key);

if (image == null)
{
    return NotFound();
}

JsonConvert.PopulateObject(values, image);

if (TryValidateModel(image))
{
    if (image.IsMainImage)
    {
        // Check if a different Image is already flagged as the Record's MainImage.
        RecordImage oldMainImage = await _context.RecordImage
            .SingleOrDefaultAsync(a => a.RecordId == image.RecordId && a.IsMainImage && a.RecordImageId != image.RecordImageId);

        // Clear old MainImage.
        if (oldMainImage != null)
        {
            oldMainImage.IsMainImage = false;
        }
    }

    await _context.SaveChangesAsync();

    return Ok(); 
}

return BadRequest(ModelState);
}

Однако, это терпит неудачу за исключением:

Невозможно сохранить изменения, так как в данных, которые необходимо сохранить, была обнаружена циклическая зависимость

Я смог исправить это, отсоединив обновленное изображение и сохранив изменения в старом MainImage, а затем снова прикрепивImage:

[HttpPut]
public async Task<IActionResult> Put(Guid key, string values)
{
RecordImage image = await _context.RecordImage.FindAsync(key);

if (image == null)
{
    return NotFound();
}

JsonConvert.PopulateObject(values, image);

if (TryValidateModel(image))
{
    // Use a Transaction as we need to call SaveChanges() more than once in this operation.
    using (var transaction = await _context.Database.BeginTransactionAsync())
    {
        // Image being updated needs to be detached before modifying and saving other entities.
        _context.Entry(image).State = EntityState.Detached;

        if (image.IsMainImage)
        {
            // Check if a different Image is already flagged as the Record's MainImage.
            RecordImage oldMainImage = await _context.RecordImage
                .SingleOrDefaultAsync(a => a.RecordId == image.Record && a.IsMainImage && a.RecordImageId != image.RecordImageId);

            // Clear old MainImage.
            if (oldMainImage != null)
            {
                oldMainImage.IsMainImage = false;
            }
        }

        // Save changes to other Images before reattaching and saving changes to the Image
        // being updated.
        await _context.SaveChangesAsync();

        _context.Entry(image).State = EntityState.Modified;
        await _context.SaveChangesAsync();

        transaction.Commit();

        return Ok(); 
    }
}

return BadRequest(ModelState);
}

Это работает и дает мне то, что мне нужно, но мне не совсем удобно, потому что я не понимаю, почему.Раньше мне казалось, что все, что я делал, обновлял несколько RecordImage в контексте, устанавливая один IsMainImage на true, а другой IsMainImage на false.Я не пытаюсь обновить ни родителей, ни детей, поскольку я даже не Including() в контексте.Что может быть источником этой круговой зависимости?

...