gpt4 book ai didi

c# - 在具有导航属性的表单中使用 TryUpdateModelAsync 时出错

转载 作者:行者123 更新时间:2023-12-04 10:00:58 24 4
gpt4 key购买 nike

假设我有一个包含以下模型结构的表单:

TestRecord.cs

class TestRecord {
public string Id { get; set; }
public string RecordName { get; set; }
...other props
public ICollection<RtdbFiles> RtdbFiles { get; set; }
}

其中对应的 RtdbFile包含以下 Prop :

RtdbFile.cs
class RtdbFile {
public int Id { get; set; }
public string Filename { get; set; }
...other props
}

当我 POST这个模型到我的 Controller 更新,我收到以下错误:
The instance of entity type 'RtdbFile' cannot be tracked because another instance with the key value '{Id: 2021}' is already being tracked
所以看起来两个相同的 RtdbFile被附加到上下文中。这是我的 Controller 方法的格式:
[HttpPost("UpdateMilestones")]
public async Task<IActionResult> UpdateMilestones(string testRecordId)
{

db.ChangeTracker.LazyLoadingEnabled = false;

var record = db.TestRecords
.Include(tr => tr.RtdbFiles)
.FirstOrDefault(tr => tr.TestRecordId == testRecordId);

if (await TryUpdateModelAsync(record))
{
await db.SaveChangesAsync();
}

return RedirectToAction("Milestones", new { id = testRecordId });
}

TryUpdateModelAsync()不能用 One-to-Many 处理情况关系?何时复制 RtdbFile被添加到上下文中?我已经 已禁用 延迟加载并急切加载 RtdbFiles .这与 Contoso University example by Microsoft 中所做的类似但不同之处在于他们急切加载的属性是 One-to-One关系。

我怎样才能解决这个问题?谢谢!

编辑以显示 Razor 页面:

更新里程碑.cshtml
@model rtdb.Models.TestRecord
@addTagHelper *, rtdb

<input type="hidden" asp-for="@Model.TestRecordId" />

<div class="form-section-text">Milestones & Tracking</div>

<!--unrelated inputs removed -->

<div class="form-group">
<vc:file record="@Model" type="@RtdbFile.AttachmentType.TPR" approvers="true"></vc:file>
</div>
RtdbFiles被抽象出来以查看组件:

文件 View 组件
@model rtdb.Models.ViewModels.FileViewModel
@addTagHelper *, rtdb
@using HtmlHelpers.BeginCollectionItemCore

<div class="form-group attachments">
<div class="link-header">@(Model.AttachmentType.ToString("G"))</div>
<div class="row">
<div class="col-sm-12">
@if (Model.TestRecord.RtdbFiles.Count > 0)
{
foreach (var file in Model.TestRecord.RtdbFiles.Where(f => f.IsDeleted != true && f.Type == Model.AttachmentType && f.TestRecordId == Model.TestRecord.TestRecordId).ToList())
{
<div class="attachment">
@using (Html.BeginCollectionItem("RtdbFiles"))
{
<div class="form-group">
<div class="form-row">
<input asp-for="@file.Id" hidden />
<input asp-for="@file.Type" hidden />
<div class="col-sm-6">
@if (@file.Id < 1)
{
<input class="FileInput" asp-for="@file.UploadedFile" type="file" />
}
else
{
<div><span data-file-id="@file.Id"><a href='@Url.Action("Download", "RtdbFiles", new { id = file.Id })'>@file.Filename (@file.Type.ToString("G"))</a></span></div>
}
</div>
<div class="col-sm-6">
<div>
<label asp-for="@file.FileApproverPersonnel" class="col-form-label col-form-label-sm">Approvers:</label>
<input asp-for="@file.FileApproverPersonnel" class="form-control file-approver-personnel ldap-tags" />
</div>
</div>
</div>
</div>
}
</div>
}
}
<div id="@(Model.AttachmentType.ToString("G"))s"></div>
<button type="button" class="add-file btn btn-primary" data-test-type="Other" data-attachment-type="TPR" data-container="@(Model.AttachmentType.ToString("G"))s">Add @(Model.AttachmentType.ToString("G"))</button>
<small style="display: block; margin-top: 6px">File size limit: 100MB</small>
</div>
</div>
</div>

最佳答案

显而易见的是TryUpdateModelAsync或者 ChangeTracker string 有一些问题外键。首先,我强烈建议您将 PrimaryKey 更改为 int因为 EF 在这种情况下会表现出一些奇怪的行为。
但是如果你坚持,我尝试了一些方法,最后达到了这个方法:
使用 AsNoTracking 阻止对象跟踪并使用 context.Update根据 Controller 模型更新记录后

根据您的最新型号,这是我的示例,效果很好:

楷模:

public class TestRecord
{
public string Id { get; set; }
public string RecordName { get; set; }

public virtual IList<RtdbFile> RtdbFiles { get; set; }
}

public class RtdbFile
{
public int Id { get; set; }
public string TestRecordId { get; set; }
public string Filename { get; set; }
}

Razor 页面:

备注 :这部分对你的结果有最重要的影响。特别 RtdbFiles[{i}].IdRtdbFiles[{i}].Filename您的 View 必须将名称完全相同的项目和值发送到服务器对象才能正确生效:
@model Jordan.TestRecord

@using (Html.BeginForm("UpdateMilestones", "Home", FormMethod.Post))
{
@Html.HiddenFor(p => p.Id);

@for (int i = 0; i < Model.RtdbFiles.Count; i++)
{
@Html.Hidden($"RtdbFiles[{i}].Id", Model.RtdbFiles[i].Id);
@Html.TextBox($"RtdbFiles[{i}].Filename", Model.RtdbFiles[i].Filename);
}
<button type="submit">Save</button>
}

Controller :
namespace Jordan
{
[Route("")]
public class HomeController : Controller
{
private readonly AppDbContext context;

public HomeController(AppDbContext context)
{
this.context = context;
context.Database.EnsureCreated();
}

[HttpGet]
public IActionResult Index()
{
var sampleRecord = context.TestRecords
.Include(r => r.RtdbFiles)
.FirstOrDefault();

return View(sampleRecord);
}

[HttpPost]
[Route("UpdateMilestones")]
public async Task<IActionResult> UpdateMilestones(int Id)
{
context.ChangeTracker.LazyLoadingEnabled = false;

var record = context.TestRecords
.Include(tr => tr.RtdbFiles)
.AsNoTracking()
.FirstOrDefault(tr => tr.Id == Id);

if (await TryUpdateModelAsync(record))
{
context.Update(record);
await context.SaveChangesAsync();
}

return RedirectToAction("Index");
}
}
}

关于c# - 在具有导航属性的表单中使用 TryUpdateModelAsync 时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61826136/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com