【问题标题】:Using a viewmodel which ignores the properties from the model使用忽略模型属性的视图模型
【发布时间】:2018-06-15 09:17:18
【问题描述】:

我正在使用实体框架和 MVC(如果重要的话,都是 CORE)来制作网站。使用模型并将其直接绑定到视图很好,所有 CRUD 操作都可以正常工作,一切都很可爱。

我想使用几个页面来访问模型,以便网站看起来更好,因此将控件拆分到单独的视图中并为每个视图添加相应的视图模型,所以我的项目看起来像这样

-Model
--CustomerModel
-ViewModel
--CustomerNameVM
--CustomerAddressVM
-View
--CustomerNameView
--CustomerAddressView

CustomerModel 有许多属性

Forename
Surname
Address
Postcode

在 CustomerNameVM 中包含名字和姓氏,在 CustomerAddressVM 中包含地址和邮政编码。姓氏在模型中定义为[Required],但在 CustomerNameVM 中没有定义,我认为这是正确的做法。

我正在努力将模型加载到视图模型中,然后在我在 CustomerAddressView 中编辑地址详细信息时尝试保存它,因为当我尝试保存时它会出错,因为视图模型不包含姓氏(来自model),因此它为 null,因此不符合 [Required] 标准。

我尝试了一些方法来尝试克服这种情况:-

  • Jeffrey Palermo 的洋葱架构
  • 存储库
  • 领域模型

在所有最终都遇到相同问题的其他人中,我无法保存地址,因为姓氏为空。

如何忽略视图模型中未引用的模型属性的验证标准? 或者如何仅加载和引用视图模型中存在的模型属性?

编辑

对于那些不断询问代码的人,哪个代码集?我现在已经尝试了其中的 30 个,但没有一个能胜任。你想要其中的哪一个?我试图大致了解这应该如何工作,因为没有任何方法、文档和相关示例功能。

这是 10 个代码集的首发,它与其他 29 个代码集不同,但它是代码并且可能是最短的。 控制器

    [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Step2Address(int? id, [Bind("CustomerID,txtAddress,txtPostcode")] VMAddress VMAddress) {
    
            if (ModelState.IsValid) {
//the saving code
            }
            return View(VMAddress);
        }

模型

  public class clsCustomer {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int CustomerID { get; set; }
    
        public string Forename { get; set; }
        [Required]
        public string Surname { get; set; }
        public string Address { get; set; }
        public string Postcode { get; set; }

视图模型

  public class VMAddress {

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CustomerID { get; set; }

    public string Address { get; set; }
    public string Postcode { get; set; }
}

视图

@model theProject.Models.VMStep2Contact

    <form asp-action="Step2Address">
        <input type="hidden" asp-for="ComplaintID" />
        <input asp-for="txtAddress"/>
        <input asp-for="txtPostcode"/>
        <input type="submit" value="Save" />

上下文

  public class ContextCustomer : DbContext {
        public ContextCustomer(DbContextOptions<ContextCustomer> options) : base(options) {

        }
        public DbSet<clsCustomer> Customer{ get; set; }
    }

点击网页上的“保存”会立即调用控制器,它会点击第一行if (ModelState.IsValid),并且由于未设置姓氏并且是[Required],ModelState 无效,因此不会尝试保存。

【问题讨论】:

  • 您能否提供更多代码的实际示例?尝试保存此数据的控制器操作是什么?您要保存哪些数据?如果您确实有一个操作需要保存具有空值的记录,那么显然首先不需要该值。
  • 看起来您必须将Surname 专门标记为未修改,但如果不查看代码就很难判断。
  • 姓氏在模型级别总体上是必需的,但由于它没有在地址页面上输入/编辑/触摸(因为为什么我需要将姓氏放在地址页面上)我只需要忽略它。我有大约 30 个不同的项目,试图使用控制器、模型、域控制器、视图模型和随机其他功能和技术(如 IoC)中的各种方法组合来达到相同的目的,但我不想要使水浑浊。我愿意接受任何可行的方式。
  • @GertArnold 我如何将其标记为未修改?
  • @Dave:如果没有一个实际的例子来说明问题的原因,我们所能提供的只是一般性建议。诸如“如果您的数据需要一个值,请在此处设置一个值”之类的建议。或“如果您有一个没有可用值的有效案例,请不要将其设为必需。”

标签: asp.net-core-mvc entity-framework-core


【解决方案1】:

我实际上并不了解问题所在,而且如果没有代码,就不可能说出您可能做错了什么。一般来说,你应该没有任何问题,因为你使用的是视图模型。

当然,视图模型不会直接保存到数据库中,因此它必须映射到您将要保存的实际实体类。在编辑的情况下,您应该从数据库中检索所有相关实体,将任何发布的值映射到这些实体的适当属性上,然后将这些实体保存回数据库。如果您这样做,大概客户模型应该已经包含Surname 和其他必需的属性,而您只需要修改/设置地址属性。

如果您正在创建,那么,您不能只获取地址信息。您还需要名称,因此为此,您需要传递一个至少包含所有必需字段的视图模型,以便您拥有实际保存实体所需的所有信息。

如果您尝试创建一个多步骤表单,在其中收集多个帖子的所有信息,那么您只需将发布的数据保存在数据库以外的其他位置,直到您有足够的数据来实际保存实体到数据库。这通常通过Session/TempData 完成。

【讨论】:

  • 理解问题有多难?我无法保存我的视图模型,因为它不包含姓氏。所以你说 onload 我加载整个模型然后将副本放入相关属性的视图模型中,然后 onsave 我再次加载整个模型从视图模型更改模型的相关部分(在执行modelstate.isvalid 检查之前,然后保存模型?如果是,viewmodel的意义何在?为什么不直接使用模型呢?
  • 所以只有在没有必填字段(或所有必填字段都在第一个视图模型中)时,视图模型才有用?
  • 没有。但我认为您并不真正了解视图模型是什么或它的用途。有两个主要目的。首先是overpost:您可以将视图模型限制为允许用户操作的属性子集。第二个是不属于实体类但视图必需的东西:IFormFile、SelectListItems 列表等。您永远不会将视图模型直接保存到数据库,因为那样它就只是一个实体。
  • 这就是我理解它们的用途,VM 包含您需要的任何来源,因此您的 VM 可以包含要显示在视图上的当前用户的登录名以及部件与此视图相关的模型的名称,在本例中为客户地址。
  • 那么您说的是多步骤表单,就像我在回答中所说的那样,您必须将其保留在 Session/TempData 之类的内容中,以便您可以在下一篇文章之后检索它并保存实体及其所需的所有组件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-30
相关资源
最近更新 更多