2017-10-18 60 views
0

我想更新一个数据库表。控制器接收具有适当数据的视图模型。如果我在这个例子中分配像每一个成员变量低于它的工作原理将视图模型中的成员变量赋值给查询结果

[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; 

这不给我错误,但它不分配成员变量。是否有捷径可寻?

谢谢!

+0

ViewModels用于验证用户输入。他们应该处理,验证并转换为实体。我也会使用db.Users.FirstOrDefaultAsync(x => x.Id == userID)。如果这个返回null,这意味着你的用户不会退出。在这种情况下,你的代码会崩溃。 – Seb

+0

你的意思是我不应该将视图模型传递给控制器​​?对不起,我不明白你的观点。 – mneumann

+0

您应该将VM从视图传递到控制器。你不应该把它从控制器传递给数据模型:)理论上,你的虚拟机和你的模型可能不同,所以它不起作用。希望我很清楚! – Seb

回答

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); 
} 

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

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

这不一定是真的。他不能在上下文中使用该模型,但他可以使用具有视图的实体(作为模型)。如果实体被模型联编程序正确绑定,那么您总是可以来回传递实体并将其重新附加到上下文,并将其状态设置为已修改,然后保存更改。我不推荐它,但它是可行的。 – JuanR

+1

霍拉胡安。是的,我同意它是可行的,但我也不推荐它,因为在数据库实体更改时更难维护,也可能发送不打算显示但仍可通过监视HTTP请求拦截的属性。此外,您可能会反复发送不必要的数据,这将不必要地增加带宽。 – Isma

2

一个可能的解决方案是使用AutoMapper,只要属性的名称和类型相同,它就会自动将属性从一个对象映射到另一个对象。所以,你可以做一些这取决于属性名称在您的类(你也可以自定义地图,如果你的属性differnetly命名),如:

//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 。这是一个广泛使用的工具,它是有据可查的。

0

这听起来像模型绑定不工作像你期望的那样。您可能需要编写自定义模型绑定器。下面的例子是从here。这个例子从DefaultModelBinder继承,然后使用反射来ONLY倍率时,它的指定类型的绑定(在下面的例子中HomePageModels,但会是您的视图模型或特定视图模型对象 - 即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); 
      } 
     } 

    }