2013-11-01 61 views
1

假設給定了html表的部分視圖,則存在每個錶行的嵌套局部視圖,如下所示:如何將IEnumerable <SelectListItem>集合傳遞給每個請求只有一個數據庫查詢的MVC部分視圖

外局部視圖

<table> 
<thead> 
    <tr> 
    <th>Item Name</th> 
    <th>Cost</th> 
    <th>Category</th> 
    </tr> 
</thead> 
<tbody> 
@for (int i = 0; i < Model.PurchaseItems.Count; i++) 
{ 
    @Html.Partial("_PurchaseItemsDetail", Model.PurchaseItems[i]) 
}  
</tbody> 
</table> 

內局部視圖,注意:此局部視圖也可以由外視圖在單個請求中多次使用,然而,它也可以僅一次如果使用AJAX

請求使用
<tr id="@Model.ID"> 
    <td>@Html.TextBoxFor(x => x.ItemName)</td> 
    <td>@Html.TextBoxFor(x => x.Cost)</td> 
    <td> 
    @Html.DropDownListFor(x => x.Category, CATEGORY_COLLECTION) 
    </td> 
</tr> 

問題:鑑於此內部視圖旨在靈活,查詢數據庫並臨時存儲要與下拉列表配合使用的IEnumerable<SelectListItem>集合的最佳方法是什麼?

方法1:我可以想辦法這似乎是最簡單的,但感覺就像它違反了MVC的原則。評估在ViewData的集合內局部視圖和存儲這樣的數據庫只命中一次:

@{ 
    if (ViewData["Categories"] == null) 
    { 
     ViewData["Categories"] = API.GetCategories(); 
    } 
    } 

後來在視圖

<td> 
    @Html.DropDownListFor(x => x.Category, ViewData["Categories"]) 
    </td> 

這是很好的,因爲視圖照顧只要確定如何填充其包含的下拉菜單。它不依賴於視圖模型。

方法2:除了在返回內部局部視圖的各種控制器方法中設置ViewData外,與上面相同。這種方式似乎更符合MVC最佳實踐,但是,考慮到每個控制器方法需要正確設置ViewData並創建必要的視圖模型,它似乎更加繁瑣和混亂。

方法3這似乎大部分工作,最難維護,但大多數按照MVC原則。避免完全使用ViewData,而是在部分視圖模型中存儲對集合的引用以及其他屬性。控制器負責創建集合,然後在每個表格行的視圖模型中存儲引用。

public class PurchaseItemModel 
{ 
    public string ItemName { get; set; } 
    public decimal Cost { get; set; } 
    public string Category { get; set; } 

    // add this 
    public IEnumberable<SelectListItem> Categories { get; set; } 
} 

並且在每個控制器,服務器內視圖

// if dealing with multiple rows (GET) 
IEnumerable<SelectListItem> collection = API.GetPurchaseItemList(); 
foreach (PurchaseItemModel pim in OuterModel.PurchaseItemModels) 
{ 
    pim.Categories = collection; 
} 

// if dealing with a single row (Ajax) 
purchaseItem.Categories = API.GetPurchaseItemList(); 

然後在後面的視圖

<td> 
    @Html.DropDownListFor(x => x.Category, x.Categories) 
    </td> 

也許,這僅僅是主觀的問題,但它似乎就在那裏將是這種情況的最佳做法。有什麼想法嗎?

+1

這不是一個很好的問題 - 而不是描述模糊,抽象的情景,描述你的具體* * *的問題與支持代碼*。 –

+0

@AntP,我編輯了我的問題。也許你會發現確定的缺點已被修復。 –

+0

幹得好,現在問題好多了。 –

回答

2

繼續創建一個視圖模型類,如

public class PurchaseItemViewModel 
{ 
    public string ItemName { get; set; } 
    public decimal Cost { get; set; } 
    public string Category { get; set; } 
    public IEnumberable<Category> Categories { get; set; } 

    public PurchaseItemViewModel(PurchaseItemModel item, List<Category> categories) 
    { 
     //initialize item and categories 
    } 
} 

在控制器中得到那麼所有的項目得到所有類別然後將購買物品的視圖模型和設置的類別。所以你會將ViewModel類傳遞給視圖。

+0

我絕對同意你的答案遵循適當的MVC設計模式。然而,這必須針對將用於該視圖的每個控制器動作進行編程,但用於獲得這些選擇項目的邏輯總是相同的。是否有避免使用ViewData的特定原因? –

+0

當然,如果這是您的偏好,您可以使用viewdata。但是,建議將viewdata用於與模型或視圖模型無關的對象。 – Luke101

2

方法3是要走的路 - 但不要太複雜。有兩個屬性 - 一個PurchaseItem屬性和Categories屬性。然後實例化每個迭代並設置屬性。

寬鬆例如:

<table> 
<thead> 
    <tr> 
    <th>Item Name</th> 
    <th>Cost</th> 
    <th>Category</th> 
    </tr> 
</thead> 
<tbody> 
@for (int i = 0; i < Model.PurchaseItems.Count; i++) 
{ 
    var vm = new PurchaseItemsDetailViewModel() 
     { 
      PurchaseItem = Model.PurchaseItems[i], 
      Categories = Model.CategoriesSelectList // or whatever holds the categories select list 
     }; 
    @Html.Partial("_PurchaseItemsDetail", vm) 
}  
</tbody> 
</table> 


<tr id="@Model.PurchaseItem.ID"> 
    <td>@Html.TextBoxFor(x => x.PurchaseItem.ItemName)</td> 
    <td>@Html.TextBoxFor(x => x.PurchaseItem.Cost)</td> 
    <td> 
    @Html.DropDownListFor(x => x.PurchaseItem.Category, x.Categories) 
    </td> 
</tr> 
+0

我喜歡你使用對象初始值設定項。我仍然對它能夠做出多麼容易的事情感到驚訝。 –

+0

如果View由View創建,View Model的要點是什麼? – solipsicle

相關問題