【问题标题】:Data Passed to Controller Not Being Saved in Database传递给控制器​​的数据未保存在数据库中
【发布时间】:2017-07-31 18:32:26
【问题描述】:

我有一个“创建”ActionResult,它正在从视图传回数据,但数据没有保存到数据库中。我知道数据正在正确地传递给控制器​​,因为我已经使用调试器完成了整个过程,但是当 POST 操作完成时,数据没有保存。 “项目”已创建,但未保存用户(公共虚拟,因此它实际上存储在名为 ApplicationUserProjects 的表中)字段。该字段是在代码运行时填充的,但是一旦操作完成,数据就不会添加到该表中,据我所知,它已经完全消失了。这是来自控制器的代码:

[HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "Administrator, Project Manager, SuperUser")]
    public ActionResult Create([Bind(Include = "Id,Name")] Project project, List<string> Developers, List<string> ProjectManagers)
    {
        if (ModelState.IsValid)
        {
            db.Projects.Add(project);
            db.SaveChanges();
            var projectsHelper = new ProjectsHelper();
            foreach (var user in Developers)
            {
                projectsHelper.AssignUserToProject(user, project);
                //project.Users.Add(db.Users.FirstOrDefault(u => u.Id == user));
                //db.SaveChanges();
            }
            foreach (var user in ProjectManagers)
            {
                projectsHelper.AssignUserToProject(user, project);
                //project.Users.Add(db.Users.FirstOrDefault(u => u.Id == user));
                //db.SaveChanges();
            }


            return RedirectToAction("Index");
        }

        return View(project);
    }

foreach 循环中被注释掉的代码代表我为解决这个问题所做的不同努力,但没有成功。

这是控制器使用的辅助方法:

public bool AssignUserToProject(string userId, Project project)
        {
            if (!IsUserAssignedToProject(userId, project))
            {
                project.Users.Add(db.Users.FirstOrDefault(u => u.Id == userId));
                //project.Users.Add(user);

            }

            if (IsUserAssignedToProject(userId, project))
            {
                db.SaveChanges();
                return true;
            }
            else
            {
                return false;
            }
        }

我不知道这是否重要,但这里是处理这些输入字段的视图部分:

<div class="form-horizontal">
    <h4>Project</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="form-group">
        @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control", style = "max-width:300px;" } })
            @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
        </div>
    </div>
    <div class="form-group">
        @*@Html.LabelFor(model => model.Users, htmlAttributes: new { @class = "control-label col-md-2" })*@
        @Html.Label("Developers", htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.ListBox("Developers", null, htmlAttributes: new { @class = "form-control", style = "max-width:300px;" })
            @Html.ValidationMessageFor(model => model.Users, "", new { @class = "text-danger" })
        </div>
    </div>
    <div class="form-group">
        @*@Html.LabelFor(model => model.Users, htmlAttributes: new { @class = "control-label col-md-2" })*@
        @Html.Label("Project Managers", htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.ListBox("ProjectManagers", null, htmlAttributes: new { @class = "form-control", style = "max-width:300px;" })
            @Html.ValidationMessageFor(model => model.Users, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</div>

提前谢谢你!

编辑: 如果我移动 db.SaveChanges();在 foreach 块下方的任何位置行,当到达该行时,我收到此错误:“EntityFramework.dll 中发生'System.InvalidOperationException'类型的异常,但未在用户代码中处理{“两个对象之间的关系不能定义是因为它们附加到不同的 ObjectContext 对象。"}"

【问题讨论】:

  • 执行所有操作,最后添加db.SaveChanges(),重定向可以解决您的问题。从所有其他地方删除db.SaveChanges()
  • 您不需要多次调用 SaveChanges()。如图here 所示,编写您的对象图并一次性保存。对于现有的孩子,您可能需要设置他们的entity state,或者您可以通过外键而不是导航属性进行更新。

标签: c# asp.net-mvc entity-framework


【解决方案1】:

对我来说,您代码中的条件是错误的。它必须是这样的:

public bool AssignUserToProject(string userId, Project project)
{
    if (!IsUserAssignedToProject(userId, project))
    {
        project.Users.Add(db.Users.FirstOrDefault(u => u.Id == userId));
        db.SaveChanges();
        return false;
    }

    return true;            
}

添加实体后,您必须调用 SaveChanges 才能真正将数据保存在数据库中。

【讨论】:

  • 这似乎并没有改变任何行为。数据仍未保存。
  • 您是否共享您的上下文实例?还是每个类都有自己的上下文?
  • 每个类都有自己的上下文。
【解决方案2】:

在您的AssignUserToProject 函数中更改行

project.Users.Add(db.Users.FirstOrDefault(u => u.Id == userId));

project.Users.Add(db.Users.FirstOrDefault(u => u.Id.Equals(userId)));

比较数据库中的字符串。

这假设 u.Id 字段也是一个字符串。否则,您需要在相等比较之前将该字段解析为适当的数据类型。

编辑

还要检查 IsUserAssignedToProject 中的所有相等操作,以确保它正确地比较了该函数内任何 LINQ 查询中的用户 ID。

【讨论】:

  • 这似乎并没有改变任何行为。数据仍未保存。
【解决方案3】:

除了“db.Projects.Add(project)”在错误的位置保存所有数据之外,问题还与控制器类和帮助程序类中的上下文不同有关。这是控制器中实际工作的代码的清理版本。不需要使用辅助方法,所以现在事情变得更整洁了。

[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Administrator, Project Manager, SuperUser")]
public ActionResult Create([Bind(Include = "Id,Name")] Project project, List<string> Developers, List<string> ProjectManagers)
{
    if (ModelState.IsValid)
    {
        foreach (var user in Developers)
        {
            project.Users.Add(db.Users.FirstOrDefault(u => u.Id == user));
        }
        foreach (var user in ProjectManagers)
        {
            project.Users.Add(db.Users.FirstOrDefault(u => u.Id == user));
        }
    }
    db.Projects.Add(project);
    db.SaveChanges();
    return RedirectToAction("Index");

}

【讨论】:

  • 您可能更喜欢对每个与数据库相关的操作使用帮助程序,因此它们都在同一个地方(更整洁)并且更容易测试所有这些操作。
猜你喜欢
  • 1970-01-01
  • 2020-12-28
  • 2020-09-17
  • 1970-01-01
  • 2015-09-08
  • 1970-01-01
  • 2021-09-02
  • 2018-03-20
  • 1970-01-01
相关资源
最近更新 更多