繁体   English   中英

如何传递IEnumerable <SelectListItem> 收集到MVC部分视图,每个请求只有一个数据库查找

[英]How to pass IEnumerable<SelectListItem> collection to a MVC Partial View with only one database lookup per request

假设给定html表的局部视图,每个表行都有一个嵌套的局部视图,如下所示:

外部局部视图

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

也许这只是主观问题,但似乎这种情况会有最好的做法。 有什么想法吗?

继续创建一个ViewModel类,如

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并设置类别。 因此,您将ViewModel类传递给视图。

方法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>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM