【问题标题】:ASP.NET MVC5 - Nullable model property always losing its value (null) when editing modelASP.NET MVC5 - 可空模型属性在编辑模型时总是丢失其值(空)
【发布时间】:2014-05-21 14:55:02
【问题描述】:

当我编辑我的模型时,所有属性都会正确保存,但可以为空的属性在此过程中总是会丢失其值。

我试图在我的视图中隐藏该属性:

@Html.HiddenFor(model => model.UserId)

在我的控制器的编辑方法中,我尝试:

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(ItemViewModel viewModel)
        {
            if (ModelState.IsValid)
            {
                var item= db.Items.Find(viewModel.ItemId);
                Mapper.Map<ItemViewModel, Item>(viewModel, item);
                //db.Entry(item).State = EntityState.Modified;
                if (TryUpdateModel(item))
                {
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
            }
            ViewBag.UserId = new SelectList(db.Users, "UserId", "Username", viewModel.UserId);
            return View(viewModel);
        }

我也尝试不使用 TryUpdateModel 和使用 UpdateModel(model) 方法。我什至尝试在保存更改之前手动将 ViewModel 中的属性值重新分配给 Model。

当我在整个方法中放置断点时,我可以看到该属性仍然保持其值,但一旦我点击 Save,它就会变为 null。

请注意,如果我取消注释 EntityState.Modified 行,我将不再丢失属性值,但我正在我的 DbContext 中处理这些内容(我对不同的属性有不同类型的编辑事件,并且这行代码在我的即使没有任何改变,控制器似乎也会触发我所有的编辑事件)。

请注意,这个属性也是一个外键(不确定它是否真的很重要)

【问题讨论】:

  • 我看不到您将要保存到数据库的对象传递到何处。从我可以看到您在数据库不知道的对象上调用 SaveChanges()。
  • TryUpdateModel 正在传递模型(我原来的帖子必须是错误的模型名称,我现在修复了它)。所有编辑的属性都已正确保存,因此可以正常工作。即使没有 TryUpdatModel 并且只需调用 db.SaveChanges() 方法,它也可以工作。不过,我的可空属性仍然失去了它的价值。
  • 你为什么注释掉db.Entry(item).State = EntityState.Modified
  • @ChrisPratt 我有不同的模型来处理不同类型的编辑(用于记录目的),并且即使仅假设更新了 Location 属性,这行代码也会触发所有编辑事件。不过,这确实似乎使我失去了可以为空的财产。我试图了解所有这些都是相关的,但到目前为止还没有这样做。
  • 我看到您已将模型映射到项目,但您尚未重新分配值。将重新评估添加到映射器调用中,我相信它会解决您的问题

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


【解决方案1】:

TryUpdateModel 实际上并没有对传递给它的项目做任何事情。它只是在其上运行模型验证。不管有什么价值,都留在那里。

认为我知道问题出在哪里,并且与 AutoMapper 有关。您发布的模型很可能不包含实际相关的用户对象,只是您为此发布的 id。当您将模型映射到实体时,AutoMapper 会将相关用户对象的值替换为 null,因为模型没有它。尝试将以下内容添加到您的 CreateMap

.ForMember(dest => dest.User, opts => opts.Ignore());

【讨论】:

  • 我修改了我的 automapper 配置文件如下: private class ItemMapping : Profile { protected override void Configure() { Mapper.CreateMap().ForMember(dest => dest.UserId, opts => opts.Ignore()); Mapper.CreateMap().ForMember(dest => dest.UserId, opts => opts.Ignore()); } } 但仍然无法正常工作。我的方法对吗?
  • 哦,我让它与 .ForMember(dest => dest.User, opts => opts.Ignore()); (就像你说的)而不是 .ForMember(dest => dest.UserId, opts => opts.Ignore());(就像我试图做的那样)谢谢!我想还有很多东西要学:) 是不是因为 User 是一个实体,而 UserId 只是一个属性?
  • 嗯,更多的是你想要映射的 id,因为你大概发布了那个。实体本身,您没有发布,因此您不希望 AutoMapper 映射它将在模型上具有的空值,因为没有发布任何内容。
  • 好的!因此,添加忽略 User 实体但允许映射 UserId 属性,得到它。是因为UserId是指向User实体的外键吗?
  • 再次,它只是关于发布的内容和未发布的内容。或者更一般地说,在映射到您的实体的模型上作为非空值存在的内容。当您映射到 User 的空值时,EF 会看它,“哦,你猜你想删除这个关联。”并且实际上最终会在将实体保存回数据库时将外键清空。
【解决方案2】:

我的意思是你的所有代码都是正确的,除了这一行:

 Mapper.Map<ItemViewModel, Item>(viewModel, item);

那行应该是

 item = Mapper.Map<ItemViewModel, Item>(viewModel, item);

然后在某些时候你需要将它传递给存储库:

 db.Update(item);
 db.SaveChanges();

【讨论】:

    猜你喜欢
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多