【问题标题】:Assign member variables from view model to query result将视图模型中的成员变量分配给查询结果
【发布时间】:2017-10-18 13:14:37
【问题描述】:

我想更新一个数据库表。控制器接收具有适当数据的视图模型。如果我像下面的示例中那样分配每个成员变量,它就可以工作

[HttpPost]
public ActionResult Edit(Admin_vm vm) {
    var result = (from Users in db.Users
                              where Users.ID == usrID
                              select Users
                  ).FirstOrDefault();

    result.CompanyName = vm.ModifyUser.CompanyName;
    //this is where I would assign every single member variable
    db.SaveChanges();
    return View(vm);
}

但是,我想知道是否有办法像这样直接分配视图模型对象:

result = vm.ModifyUser;

这不会给我一个错误,但它不会分配成员变量。有没有简单的方法可以做到这一点?

谢谢!

【问题讨论】:

  • ViewModel 用于验证用户输入。它们应该被处理、验证然后转换为实体。我还会使用 db.Users.FirstOrDefaultAsync(x=>x.Id == userID)。如果返回 null,则表示您的用户没有退出。在这种情况下,您的代码将会崩溃。
  • 你的意思是我不应该将视图模型传递给控制器​​?对不起,我不明白你的意思。
  • 您应该将虚拟机从视图传递到控制器。你不应该将它从控制器传递到数据模型:)。理论上,你的虚拟机和你的模型可能不同,所以它不会工作。希望我清楚!
  • 好的,我理解你的观点。如何将我的视图模型转换为实体,然后将其传递给数据模型?这不只是创建新对象然后将其传递给数据模型的额外步骤吗?编辑:我阅读了答案,实际上我听说过 AutoMapper。但由于这是一个小项目,我想我会坚持手动分配。

标签: c# asp.net-mvc linq


【解决方案1】:

您不能直接将视图模型对象设置为数据库实体对象,因为它们是不同类的对象。

相反,您可以映射每个属性,这可以手动完成(就像您现在所做的那样),使用反射或使用现有的库,例如 ValueInjecter 或 AutoMapper。

如果两个对象非常相似并且具有相同的属性名称,我会使用 ValueInjecter,因为它非常快速且易于使用,AutoMapper 慢得多但允许更复杂的映射(我遇到了严重的性能问题但是选择最适合您的方案,即速度与灵活性)。

对于您问题中的示例,以下是如何使用 ValueInjecter 执行此操作:

添加 ValueInjecter NuGet:

Install-Package ValueInjecter -Version 3.1.1.5

在你的控制器类中包含命名空间:

using Omu.ValueInjecter;

然后在你的行动中:

[HttpPost]
public ActionResult Edit(Admin_vm vm) {
    var result = (from Users in db.Users
                              where Users.ID == usrID
                              select Users
                  ).FirstOrDefault();

    result.InjectFrom(vm.ModifyUser);

    context.SaveChanges();

    return View(vm);
}

对于 Create 方法,您需要先创建对象:

User user = new User();
user.InjectFrom(vm.ModifyUser);

【讨论】:

  • 这不一定是真的。他不能将模型与上下文一起使用,但他可以将实体与视图一起使用(作为模型)。如果实体被模型绑定器适当地绑定,那么您始终可以来回传递实体并将其重新附加到上下文并将其状态设置为已修改,然后保存更改。我不推荐它,但它是可行的。
  • 你好胡安。是的,我同意这是可行的,但我也不推荐它,因为当数据库实体发生更改时会更难维护,而且您可能会发送不打算显示但仍然可以通过监视 HTTP 请求来拦截的属性.此外,您可能会来回发送不必要的数据,这会不必要地增加带宽。
【解决方案2】:

一种可能的解决方案是使用AutoMapper,只要属性的名称和类型相同,它就会自动将属性从一个对象映射到另一个对象。因此,您可以根据类中的属性名称执行此类操作(如果您的属性名称不同,您也可以定义自定义映射):

//create the map, this is normally done in a config file but can be done in many different places
Mapper.Initialize(x =>
{
        x.CreateMap<User, type of vm.ModifyUser goes here>().ReverseMap();
}

//map the vm to the user, this will update all fields on result to what is contained in vm.ModifyUser assuming properties are named and typed the same.
....db query to retrieve result... 
result = Mapper.Map<User>(vm.ModifyUser);
context.SaveChanges()

您可以通过 NuGet 包管理器添加 AutoMapper。这是一个广泛使用的工具,有据可查。

【讨论】:

    【解决方案3】:

    听起来模型绑定器没有像您预期的那样工作。您可能需要编写自定义模型绑定器。下面的例子来自here。此示例继承自 DefaultModelBinder,然后使用反射来覆盖 指定 类型的绑定(下面示例中的 HomePageModels,但将是您的 ViewModel 或特定的 ViewModel 对象 - 即 Admin_vmModifyUser)。对于其他一切,它通常绑定,这可能是首选。

    public class HomeCustomDataBinder : DefaultModelBinder
        {
    
            public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                if (bindingContext.ModelType == typeof(HomePageModels))
                {
                    HttpRequestBase request = controllerContext.HttpContext.Request;
    
                    string title = request.Form.Get("Title");
                    string day = request.Form.Get("Day");
                    string month = request.Form.Get("Month");
                    string year = request.Form.Get("Year");
    
                    return new HomePageModels
                    {
                        Title = title,
                        Date = day + "/" + month + "/" + year
                    };
    
                    //// call the default model binder this new binding context
                    //return base.BindModel(controllerContext, newBindingContext);
                }
                else
                {
                    return base.BindModel(controllerContext, bindingContext);
                }
            }
    
        } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      • 2018-11-21
      相关资源
      最近更新 更多