2017-10-18 59 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); 
      } 
     } 

    }