EF Core中关联表AssetsMixedUseTypes更新失效问题求助
问题描述
我有Asset表和MixedUseType表,通过关联表AssetsMixedUseTypes建立多对多关系。目前该关联表支持INSERT和DELETE操作,但UPDATE操作无法正常执行,找不到配置错误的位置。
相关代码文件
Asset.cs
public partial class Asset { public int AssetId { get; set; } public string AssetName { get; set; } public ICollection<AssetsMixedUseType>? AssetsMixedUseTypes { get; set; } = new List<AssetsMixedUseType>(); }
MixedUseType.cs
public partial class MixedUseType { public int MixedUseTypeId { get; set; } public string MixedUseTypeName { get; set; } public ICollection<AssetsMixedUseType>? AssetsMixedUseTypes { get; set; } = new List<AssetsMixedUseType>(); }
AssetsMixedUseType.cs
public partial class AssetsMixedUseType { public int AssetId { get; set; } public int MixedUseTypeId { get; set; } public virtual Asset? Asset { get; set; } = null!; public virtual MixedUseType? MixedUseType { get; set; } = null!; }
DatabaseContext.cs
modelBuilder.Entity<AssetsMixedUseType>(entity => { entity.HasKey(amut => new { amut.AssetId, amut.MixedUseTypeId }).HasName("PK_Mixed_Use_Types"); entity.ToTable("Assets_Mixed_Use_Types"); entity.Property(e => e.AssetId).HasColumnName("AssetID"); entity.Property(e => e.MixedUseTypeId).HasColumnName("MixedUseTypeID"); entity.HasOne(d => d.Asset).WithMany(a => a.AssetsMixedUseTypes) .HasForeignKey(d => d.AssetId) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_Assets_Mixed_Use_Types_Assets"); entity.HasOne(d => d.MixedUseType).WithMany(a => a.AssetsMixedUseTypes) .HasForeignKey(d => d.MixedUseTypeId) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_Assets_Mixed_Use_Types_Mixed_Use_Types"); });
Edit.cshtml.cs
[BindProperty] public AssetsMixedUseType AssetsMixedUseType { get; set; } = default!; public async Task<IActionResult> OnGetAsync(int? id, int? assetId) { if (id == null || assetId == null || _context.AssetsMixedUseTypes == null) { return NotFound(); } var assetsmixedusetype = await _context.AssetsMixedUseTypes.Where(m => m.MixedUseTypeId == id).Where(m => m.AssetId == assetId).FirstOrDefaultAsync(); if (assetsmixedusetype == null) { return NotFound(); } AssetsMixedUseType = assetsmixedusetype; ViewData["AssetId"] = AssetsMixedUseType.AssetId; ViewData["MixedUseTypes"] = new SelectList(_context.MixedUseTypes, nameof(MixedUseType.MixedUseTypeId), nameof(MixedUseType.MixedUseTypeName)); return Page(); } public async Task<IActionResult> OnPostAssetMixedUseTypeEditAsync() { if (!ModelState.IsValid) { return Page(); } _context.Attach(AssetsMixedUseType).State = EntityState.Modified; try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!AssetsMixedUseTypeExists(AssetsMixedUseType.AssetId)) { return NotFound(); } else { throw; } } return Page(); }
Edit.cshtml
<form method="post" asp-page-handler="AssetMixedUseTypeEdit" data-ajax="true" data-ajax-method="post" data-ajax-success="refreshPartial('GetAssetMixedUseTypes', 'MixedUseTypes-container')" data-ajax-failure="ajaxValidationHandler"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <input type="hidden" asp-for="AssetsMixedUseType.AssetId" value="@ViewBag.AssetId" /> <div class="form-group"> <label asp-for="AssetsMixedUseType.MixedUseTypeId" class="control-label"></label> <select asp-for="AssetsMixedUseType.MixedUseTypeId" class="form-control" asp-items="ViewBag.MixedUseTypes"><option disabled selected>- Select Mixed Use Type -</option></select> </div> <div class="form-group"> <input type="submit" value="Save" class="btn btn-primary" /> <a class="btn btn-secondary" href="javascript:parent.actionPaneClose();">Cancel</a> </div> </form>
问题原因与解决方案
核心问题
关联表AssetsMixedUseType的主键是复合主键(AssetId + MixedUseTypeId),EF Core不允许直接修改实体的主键值。你当前试图修改MixedUseTypeId,这属于修改主键的一部分,EF Core会判定为无效操作,不会生成UPDATE语句。同时,直接标记实体为EntityState.Modified也无法解决这个问题,因为主键变更本身不被支持。
正确处理方式
多对多关联表的“更新”本质上是删除原关联记录,再插入新的关联记录,具体步骤如下:
1. 修改后端处理逻辑
更新OnPostAssetMixedUseTypeEditAsync方法:
public async Task<IActionResult> OnPostAssetMixedUseTypeEditAsync(int originalMixedUseTypeId) { if (!ModelState.IsValid) { return Page(); } // 获取原始关联记录 var originalRecord = await _context.AssetsMixedUseTypes .FirstOrDefaultAsync(m => m.AssetId == AssetsMixedUseType.AssetId && m.MixedUseTypeId == originalMixedUseTypeId); if (originalRecord == null) { return NotFound(); } // 删除原关联,插入新关联 _context.AssetsMixedUseTypes.Remove(originalRecord); _context.AssetsMixedUseTypes.Add(new AssetsMixedUseType { AssetId = AssetsMixedUseType.AssetId, MixedUseTypeId = AssetsMixedUseType.MixedUseTypeId }); try { await _context.SaveChangesAsync(); } catch (DbUpdateConcurrencyException) { if (!_context.Assets.Any(a => a.AssetId == AssetsMixedUseType.AssetId)) { return NotFound(); } else { throw; } } return Page(); }
2. 页面传递原始主键值
在Edit.cshtml中添加隐藏字段,传递原始的MixedUseTypeId:
<form method="post" asp-page-handler="AssetMixedUseTypeEdit" data-ajax="true" data-ajax-method="post" data-ajax-success="refreshPartial('GetAssetMixedUseTypes', 'MixedUseTypes-container')" data-ajax-failure="ajaxValidationHandler"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <input type="hidden" asp-for="AssetsMixedUseType.AssetId" value="@ViewBag.AssetId" /> <!-- 添加原始MixedUseTypeId的隐藏字段 --> <input type="hidden" name="originalMixedUseTypeId" value="@AssetsMixedUseType.MixedUseTypeId" /> <div class="form-group"> <label asp-for="AssetsMixedUseType.MixedUseTypeId" class="control-label"></label> <select asp-for="AssetsMixedUseType.MixedUseTypeId" class="form-control" asp-items="ViewBag.MixedUseTypes"><option disabled selected>- 选择混合用途类型 -</option></select> </div> <div class="form-group"> <input type="submit" value="保存" class="btn btn-primary" /> <a class="btn btn-secondary" href="javascript:parent.actionPaneClose();">取消</a> </div> </form>
3. 修复辅助方法逻辑
原AssetsMixedUseTypeExists方法逻辑错误,应判断关联记录是否存在,而非Asset是否存在:
private bool AssetsMixedUseTypeExists(int assetId, int mixedUseTypeId) { return _context.AssetsMixedUseTypes?.Any(e => e.AssetId == assetId && e.MixedUseTypeId == mixedUseTypeId) ?? false; }
4. 可选:调整删除行为配置
关联表的OnDelete(DeleteBehavior.ClientSetNull)可能不符合业务逻辑,多对多关联通常使用DeleteBehavior.Cascade(删除主表时自动删除关联)或DeleteBehavior.Restrict(禁止删除关联的主表),可根据实际业务调整。
内容的提问来源于stack exchange,提问作者s15199d
相关产品推荐
相关产品推荐

