2011-07-04 28 views
5

我想知道什麼是在包含數據庫中的值而不重複任何代碼的表單上選擇列表的最佳方法。如何從數據庫值生成選擇列表?

我認爲有意義的是將這些數據加載到控制器中並將其傳遞給視圖模型,因此我可以使用SelectListFor<>或其他任何方法來生成列表。但是這意味着我必須複製GET和POST方法中的所有列表加載。我可以看到的另一種方式是將數據庫上下文傳遞到視圖模型構造函數中並讓它加載列表,但是這會帶來兩個問題:

1)視圖模型應該知道數據庫上下文嗎?

2)然後,我不能通過接受視圖模型類型作爲方法參數來使用模型綁定,因爲它沒有無參數構造函數(如果我創建了無參數構造函數,那麼它將不具有列表if我想重新顯示包含表單的視圖)。

有沒有更好的方法來做到這一點?這似乎是一個相當普遍的情況,任何建議,將不勝感激。

+0

你是什麼意思「複製GET和POST方法中的所有列表加載」?你目前的代碼是什麼樣的? –

+0

@Tom優秀的問題,我希望我可以做5投票ups這個,但+1然而 –

回答

1

我們通常通過一個ReferenceDataRepository來實現我們的查找,它在控制器中的使用與其他庫交互一樣。該存儲庫通常會接收大量主要爲靜態只讀數據的調用,因此我們可以使用所選緩存模式(Session,AppFabric等)的抽象來實現派生的CachedReferenceDataRepository。

1

爲什麼不讓你的數據庫或知識庫或業務規則 - 無論你稱之爲發回IDictionary ???

這個例子假設你有一個用戶列表,你會可以說名+姓送回他們的ID的鍵和值:

然後用這個觀點裏面....

<%= Html.DropDownListFor(model => model.UserID, new SelectList(Model.AvailableUsers, "Key", "Value",Model.UserID))%> 

model.UserID = Key 
Model.AvailableUsers = IDictionary<int,string> 

我在一些輔助代碼創建我的列表有時然後我查找使用這個幫手這些價值觀......所以有一個集中的類(通常爲靜態),將產生這些「用戶」 ......

直接將這些用戶傳遞到視圖上,或者直接傳遞給V在你的情況下,這是我推薦的

注意:你不會將數據上下文與List/Model Binding連接起來,這會使事情太複雜。只要看看在用戶名從列表中選定的用戶,然後在您的文章處理apporpriately ...

視圖模型:

public class UsersViewModel 
{ 
    public int UserID { get; set; } 
    public IDictionary<int,string> AvailableUsers{ get; set; } 
} 

在你的帖子...

[HttpPost] 
    [ValidateAntiForgeryToken] 
    [DemandAuthorization(RoleNames.AdminUser, AlwaysAllowLocalRequests = true)] 
    public ActionResult AllUsers(int UserID) 
    { 
     try 
     { 
      //save to db or whatever... 
      return RedirectToAction("Index", "Users"); 
     } 
     catch (RulesException ex) 
     { 
      ex.CopyTo(ModelState); //custom validation copied to model state 
     } 
     var _users= _service.GetUsers(); 
     return View("AllUsers", new UsersViewModel 
     { 
      UserID = UserID, 
      AvailableUsers = _users 
     }); 

    } 
0

好了,我的觀點是,你必須在你的視圖模型中有上下文或者存儲庫對象才能在這種情況下保持乾燥。此外,你的視圖模型不應該知道你的數據庫也是正確的。爲了解決這個問題,你可以有視圖模型的構造函數接受像

public Interface IUserRepository 
{ 
    public IEnumerable<User> GetAll(); 
} 

的接口,你可以有你的視圖模型像

public class CreateVM 
{ 
    private IUserRepository _repo; 
    public CreateVM(IUserRepository repo) 
    { 
     _repo = repo; 
    } 
    public IEnumerable<SelectListItem> AvailableUsers 
    { 
     get{ 
      return _repo.GetAll().Where(x=>x.isAvailable).Select(x=>new SelectListinItem{Text = x.UserName, Value = x.UserID}); 
      } 
    } 
} 

最後一塊拼圖是你的DI設置。告訴你的IOC容器在你的視圖模型的構造函數中實例化時注入IUserRepository。我不知道當模型綁定器創建視圖模型的實例時DI是否可以工作,但至少在理論上它至少存在。您的viewmodel不知道您的存儲庫,但只有一個界面和您的列表創建在一個點,所以你也幹。

+2

每個自己的,但我不喜歡在ViewModel內引用存儲庫。我們相信它的控制器的工作是通過只注入到控制器中的存儲庫向ViewModel提供它需要的所有信息。 –

+0

@達斯你是對的,但我們不會保持乾爽。它的悖論不是它(放棄一種有利於其他模式的模式) –

0

我路過IRepository到視圖模型中看到的最大的問題是,這很容易導致性能問題 - 選擇N + 1的是那麼自然在這種情況下,這是很難避免。您希望儘可能少的rountrips到DB請求,並通過所有這些多級別ViewModels傳遞IRepository只是沒有幫助。

相反,您可以引入ViewModel工廠,它負責創建所需類型的ViewModels。 MyViewModelFactory將取決於IRepository,並將創建MyViewModel這只是普通的DTO。

相關問題