Razor pages ef core-CRUD如何修改嵌套集合上的Edit?数据库冲突异常



在我的项目中,我使用带有EF Core的LazyLoading,我有两个实体:

    public class OfferEntity : BaseEntity
    {
        public string Category { get; set; }
        public virtual List<ImagePreviewEntity> ImagePreviews { get; set; }
    }
    public class ImagePreviewEntity: BaseEntity
    {
        public string PreviewUrl { get; set; }
    }

我可以通过这种方式从创建剃刀页面创建它们(使用js动态添加新行(:

        <div class="form-group">
            <input asp-for="OfferEntity.Category" class="form-control" />
        </div>
        <div id="ImagePreviews" class="form-group">
            <input id="addImageBtn" type="button" value="Add new">
            @for (var i = 0; i < Model.OfferEntity.ImagePreviews.Count; i++)
            {
                <input asp-for="OfferEntity.ImagePreviews[i].PreviewUrl" class="form-control" />
            }
        </div>

在standart Create.cshtml.cs中,我只为绑定模型添加了第1个实体创建:OfferEntity = new() { ImagePreviews = new() { new() } };

而且在编辑之前,它运行得非常好。我的编辑剃刀页面与创建页面相同。我的编辑.cshtml.cs:

    public async Task<IActionResult> OnGetAsync(string id)
    {
        OfferEntity = await _context.Offers.Include(x => x.ImagePreviews).FirstOrDefaultAsync(m => m.Id == id);
        return Page();
    }
    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
            return Page();
        //await _context.Offers.Include(p => p.ImagePreviews).LoadAsync();
        var toRemove = OfferEntity.ImagePreviews
            .Where(x => string.IsNullOrEmpty(x.PreviewUrl))
            .ToList();
        _context.Attach(OfferEntity).State = EntityState.Modified;
        _context.ImagePreviews.RemoveRange(toRemove);
        await _context.SaveChangesAsync();
        
        return return RedirectToPage("./Index");
     }

有两个问题我无法解决:

  1. ImagePreviews更改不会保存在父实体上
  2. 删除空的ImagePreviews导致DbUpdateConcurrencyException:数据库操作应影响1行,但实际影响0行

我尝试过的:

  1. 从scopeFactory注入数据库上下文
  2. 将已删除的实体标记为状态=已删除
  3. 使用include(imagePreview(直接从上下文加载数据库集,而不是附加
  4. 正在从OfferEntity.ImagePreviews集合中删除实体
  5. 手鼓跳舞

我缺少什么?

在与EF斗争了一天后,找到了一个不优雅但有效的解决方案。其中一些问题是:

  1. 我的新实体没有ID
  2. 我在"编辑剃刀"页面中的现有实体没有附加ID
  3. 我曾多次尝试附加嵌套属性

这是我的OnPostAsync:

    public async Task<IActionResult> OnPostAsync()
    {
        if (!ModelState.IsValid)
            return Page();
        var newImages = OfferEntity.ImagePreviews
            .Where(x => string.IsNullOrEmpty(x.Id))
            .ToList();
        foreach (var imagePreviewEntity in newImages)
        {
            imagePreviewEntity.Id = Guid.NewGuid().ToString();
            await _context.ImagePreviews.AddAsync(imagePreviewEntity);
        }
        _context.Attach(OfferEntity).State = EntityState.Modified;
        var relatedPreviewIds = OfferEntity.ImagePreviews.Select(x => x.Id).ToList();
        var previews = await _context.ImagePreviews
            .Where(x => relatedPreviewIds.Contains(x.Id))
            .ToListAsync();
        previews.ForEach(entity =>
        {
            _context.Entry(entity).CurrentValues.SetValues(OfferEntity.ImagePreviews.First(p => p.Id == entity.Id));
            if (string.IsNullOrEmpty(entity.PreviewUrl))
            {
                _context.Attach(entity).State = EntityState.Deleted;
                return;
            }
            if (_context.Entry(entity).State != EntityState.Added)
                _context.Attach(entity).State = EntityState.Modified;
        });
        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            if (!OfferEntityExists(OfferEntity.Id))
                return NotFound();
            throw;
        }
        return RedirectToPage("./Index");
    }

我觉得一定有更清洁的解决方案。只写那么多代码来从嵌套列表中添加/删除实体是疯狂的。

相关内容

最新更新