У меня есть таблица с именем 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()
в контексте.Что может быть источником этой круговой зависимости?