【发布时间】:2021-10-02 17:06:37
【问题描述】:
这有点奇怪,我 90% 确定这是一个错误,但你永远不知道。
我正在为学生提供辅导课程,并试图让他们了解如何使用 EF Core 和 ASP.NET Core 3.1。由于他们是初学者,因此我不想为每个视图编写模型,以去除视图不需要的所有 EF Core 实体数据。相反,我只是让他们将实体模型类直接传递给视图,并在他们从视图中POST 时将其直接传递回控制器。
我试图向他们展示如何将 Comment 添加到 Review 实体,但我遇到了一个奇怪的问题。
鉴于以下GET 操作:
[HttpGet]
public IActionResult Write([FromRoute] int id)
{
return View(new Comment
{
ReviewId = id
});
}
还有以下视图:
@model Comment
@{
ViewBag.Title = "Add a comment";
}
<nav>
<a asp-controller="Home" asp-action="Index">Back</a>
</nav>
<h1>ID: @Model.Id</h1>
<form method="post" asp-controller="Comments" asp-action="Write">
@Html.HiddenFor(c => c.ReviewId)
@Html.LabelFor(c => c.Content)
@Html.TextAreaFor(c => c.Content)
<button type="submit">Submit</button>
</form>
Comment 的 ID 会自动设置为我数据库中的最后一个 ID,即使它没有被 View 修改或由 GET 方法设置,只要它到达我的控制器的 POST行动。
[HttpPost]
public IActionResult Write(Comment model)
{
// Using a debugger, "model" has an ID equal to that of the
// last Comment in my database as soon as we enter this method...
var review = _context.Reviews
.Include(r => r.Comments)
.FirstOrDefault(r => r.Id == model.ReviewId);
if (review != null)
{
review.Comments.Add(model);
_context.Update(review);
_context.SaveChanges(); // <-- Causes a primary key conflict error because of "model.Id"'s value
}
}
我对这种行为感到有点困惑,但我并没有永远将 EF Core 模型传递给控制器(我们通常编写视图特定的模型来去除我工作的不需要的数据),所以也许这个是正常行为吗?但它感觉对我来说就像一个错误。
我已经找到了一个“修复”,只需明确地绑定我想要的属性:
[HttpPost]
public IActionResult Write([Bind("Content, ReviewId")]Comment model)
但我想知道为什么model 的Id 属性一碰到我的控制器就会自动设置为最后一个Comment 实体的Id。
【问题讨论】:
-
@GertArnold,当你第一次回复我的帖子时,我正在写我的答案。我发现了这个问题。这是因为我的签名中没有
[FromForm],并且框架从 URL 中推断出模型的 ID(我猜是因为默认端点路由映射中的{id?}位与model.Id属性名称匹配?),它具有父评论的 ID(不会因为我们添加了更多评论而改变)。这意味着向同一个Review对象添加更多Comments 最终会与Review.Id的值发生冲突。 -
我怀疑会发生这样的事情,但不知道如何发生。所以就是这样。
-
我从来没有在网络核心中使用过 [FromForm]。但它通常仅在需要指向源的特殊情况下使用(在同一操作中,一些参数来自路由,一些来自查询字符串,一些来自表单)。
标签: c# asp.net asp.net-mvc asp.net-core entity-framework-core