3

我有我合併成一個ViewModel,所以我可以一次編輯所有數據的兩個自動生成的數據庫模型(產品產品詳細)。迭代的ICollection從視圖模型中查看

讓我感到困惑的是我應該在視圖內通過ICollection Product_PetactCategoryAttributes(在ProductDetail模型中)迭代的部分,以允許.NET自動將屬性綁定到ViewModel。我試過以及foreach循環,但沒有任何成功,因爲正在使用錯誤的名稱(需要自動綁定)創建控件。

產品型號

public partial class Product 
{ 
    public Product() 
    { 
     this.ProductDetail = new HashSet<ProductDetail>(); 
    } 

    public int idProduct { get; set; } 
    public int idProductCategory { get; set; } 
    public string EAN { get; set; } 
    public string UID { get; set; } 
    public bool Active { get; set; } 

    public virtual ProductCategory ProductCategory { get; set; } 
    public virtual ICollection<ProductDetail> ProductDetail { get; set; } 
} 

產品詳情模型

public partial class ProductDetail 
{ 
    public ProductDetail() 
    { 
     this.Product_ProductCategoryAttribute = new HashSet<Product_ProductCategoryAttribute>(); 
    } 

    public int idProductDetail { get; set; } 
    public int idProductCategory { get; set; } 
    public int idMeta { get; set; } 
    public int idProduct { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 

    public virtual Meta Meta { get; set; } 
    public virtual Product Product { get; set; } 
    public virtual ICollection<Product_ProductCategoryAttribute> Product_ProductCategoryAttribute { get; set; } 
    public virtual ProductCategory ProductCategory { get; set; } 
} 

ProductViewModel - 一個產品可以有很多產品詳細

public class ProductViewModel 
{ 
    public Product Product { get; set; } 
    public List<ProductDetail> ProductDetails { get; set; } 

} 

視圖(一些碼被有意地省略)

@for (int i = 0; i < Model.ProductDetails.Count(); i++) 
{ 
    @Html.TextAreaFor(model => model.ProductDetails[i].Description, new { @class = "form-control", @rows = "3" }) 

    @for (int j = 0; j < Model.ProductDetails[i].Product_ProductCategoryAttribute.Count(); j++) 
    { 
     @Html.HiddenFor(model => model.ProductDetails[i].Product_ProductCategoryAttribute.ElementAt(j).idProductCategoryAttribute) 
     @Html.TextBoxFor(model => model.ProductDetails[i].Product_ProductCategoryAttribute.ElementAt(j).Value, new { @class = "form-control" }) 
    } 
} 

for循環所有第二外部控制被正確命名例如。 產品詳細[0]。說明,然而for循環第二內產生控制由屬性值,其在這種情況下是價值idProductCategoryAttribute得到他們的名字。如果我沒有錯,一個解決方案會將ICollection轉換爲IList,但是自動生成模型我不認爲這是最好的選擇。

回答

2

您不能在HTML助手的lambda內使用ElementAt()。將生成的名稱只是沒有索引的字段的名稱,它允許填充發布的值。

您應該使用索引遍歷整個視圖模型,以便生成的名稱實際匹配。

所以這個:

@Html.HiddenFor(model => model.ProductDetails[i].Product_ProductCategoryAttribute.ElementAt(j).idProductCategoryAttribute) 

應該是這樣,還是類似:

@Html.HiddenFor(model => model.ProductDetails[i].Product_ProductCategoryAttribute[j].idProductCategoryAttribute) 

至於改變模型從ICollectionIList,這將是罰款,從ICollectionIList繼承。但正如你所說它是自動生成的,如果你使用的是代碼優先的實體框架或類似的東西,那可能就沒問題了。

真正的解決方案是將您的傳入模型(視圖模型)映射到自動生成的ICollection<>列表並返回,具體取決於您是post ing還是get丁。

在下面的示例中,我們將發佈的值映射到自動生成的Product對象並對其進行處理。

/// 
    /// ProductViewModel incoming model contains IList<> fields, and could be used as the view model for your page 
    /// 
    [HttpPost] 
    public ActionResult Index(ProductViewModel requestModel) 
    { 
     // Create instance of the auto generated model (with ICollections) 
     var product = new Product(); 

     // Map your incoming model to your auto generated model 
     foreach (var productDetailViewModel in requestModel) 
     { 
      product.ProductDetail.Add(new ProductDetail() 
      { 
       Product_ProductCategoryAttribute = productDetailViewModel.Product_ProductCategoryAttribute; 

       // Map other fields here 
      } 
     } 

     // Do something with your product 
     this.MyService.SaveProducts(product); 

     // Posted values will be retained and passed to view 
     // Or map the values back to your valid view model with `List<>` fields 
     // Or pass back the requestModel back to the view 
     return View(); 
    } 

ProductViewModel.cs

public class ProductViewModel 
{ 
    // This shouldn't be here, only fields that you need from Product should be here and mapped within your controller action 
    //public Product Product { get; set; } 

    // This should be a view model, used for the view only and not used as a database model too! 
    public List<ProductDetailViewModel> ProductDetails { get; set; } 
} 
+0

索引不能與ICollections一起使用,所以不幸的是這不是答案。 –

+2

然後這是不可能的。 ICollection沒有索引器,它需要一個索引來匹配它們。如果沒有訂單到列表,它就無法匹配特定字段.... – Luke

+0

IList繼承ICollection,因此更改模型可能會很好 – Luke

2

如果模型ICollection<T>(且無法更改爲IList<T>或在for循環使用),那麼你就需要使用自定義EditorTemplate爲typeof運算T

/Views/Shared/EditorTemplates/Product_ProductCategoryAttribute.cshtml

@model yourAssembly.Product_ProductCategoryAttribute 
@Html.HiddenFor(m => m.idProductCategoryAttribute) 
@Html.TextBoxFor(m => m.Value, new { @class = "form-control" }) 

/Views/Shared/EditorTemplates/ProductDetail.cshtml

@model yourAssembly.ProductDetail 
@Html.TextAreaFor(m => m.Description, new { @class = "form-control", @rows = "3" }) 
@Html.EditorFor(m => m.Product_ProductCategoryAttribute) 

在主視圖中

@model yourAssembly.ProductViewModel 
@using (Html.BeginForm()) 
{ 
    ... 
    @Html.EditorFor(m => m.ProductDetails) 
    ... 

EditorFor()方法將認識到集合(IEnumerable<T>),並且將使用相應的EditorTemplate包括添加索引器呈現集合中的每個項在控件name屬性中,以便在發佈時綁定集合。

自定義EditorTemplate對於複雜類型的另一個優點是它們可以在其他視圖中重複使用。您也可以通過將其定位在與控制器關聯的視圖文件夾中來創建多個EditorTemplate,例如/Views/YourControllerName/EditorTemplates/ProductDetail.cshtml

附註。在任何情況下,您都應該爲每種類型使用視圖模型,這些類型只包含要在視圖中編輯/顯示的屬性。