ASP.Net MVC 3,使用ViewModel,ViewModel不是IEnumerable的错误

时间:2012-07-30 00:18:02

标签: c# asp.net-mvc-3 viewmodel ienumerable

好的,在搜索和搜索谷歌和其他编程网站之后,我该问我第一个问题了。

我有一个视图,Index.cshtml,我需要两个模型,所以我创建了一个ViewModel,ImageViewModel.cs,两个子模型,ImageModel.cs和ProductModel.cs,并有一个控制器ImageController.cs。

对于我的生活,我无法让IEnumerable工作,我应该得到一组数据,一个可能有一个项目(产品),另一个将有很多(图像)。图像与productID相关联。

使用它后,我现在到了视图中,@ Html.DisplayFor(modelItem => item.imageTitle)抛出了imageTitle不存在的错误。

如果我恢复分散在其中的众多IEnumerable项中的任何一项,我继续传入的获取ImageViewModel不是IEnumerable而且视图期望它是。

这是什么,这是完整的代码清单:

Index.cshtml

@model IEnumerable<JustAdminIt.Areas.JBI.ViewModels.ImageViewModel>

@{
ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
    <th>
        Image Title
    </th>
    <th>
        Image Excerpt
    </th>
    <th>
        Image Description
    </th>
    <th>
        Image 
    </th>
    <th>
       Product ID
    </th>
    <th></th>
</tr>
@foreach (var item in Model) {

<tr>
    <td>
        @Html.DisplayFor(modelItem => item.Image.imageTitle)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Image.imageExcerpt)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Image.imageDescription)
    </td>
    <td>
        <img src="@Url.Content("~/Content/images/product/")@Html.DisplayFor(modelItem => item.Image.imageURL)" alt="Product Image" width="150" />
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Product.productID)
    </td>

    <td>
        @Html.ActionLink("Edit", "Edit", new { id = item.Image.imageID }) |
        @Html.ActionLink("Details", "Details", new { id = item.Image.imageID }) |
        @Html.ActionLink("Delete", "Delete", new { id = item.Image.imageID })
    </td>
</tr>
}

</table>

ProductModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Web.Mvc;

namespace JustAdminIt.Areas.JBI.Models
{
public class Product
{
    [Key]
    public int productID { get; set; }

    [Required]
    [DisplayName("Product Name")]
    public string productName { get; set; }

    [Required]
    [AllowHtml]
    [DisplayName("Product Excerpt")]
    public string productExcerpt { get; set; }

    [Required]
    [AllowHtml]
    [DisplayName("Product Description")]
    public string productDescription { get; set; }

    [DisplayName("Mark As Active")]
    public bool productActive { get; set; }

    [DisplayName("Product Add Date")]
    public DateTime? productAddDate { get; set; }

    [DisplayName("Product Inactive Date")]
    public DateTime? productInactiveDate { get; set; }

}
}

ImageModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Web.Mvc;

namespace JustAdminIt.Areas.JBI.Models
{
public class Image
{
    [Key]
    public int imageID { get; set; }

    [Required]
    public string imageTitle { get; set; }

    [AllowHtml]
    public string imageExcerpt { get; set; }

    [AllowHtml]
    public string imageDescription { get; set; }

    [AllowHtml]
    public string imageURL { get; set; }

    [Required]
    public int productID { get; set; }
}
}

ImageController.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using JustAdminIt.Areas.JBI.Models;
using JustAdminIt.Areas.JBI.ViewModels;
using JustAdminIt.Areas.JBI.DAL;
using System.IO;

namespace JustAdminIt.Areas.JBI.Controllers
{ 
public class ImageController : Controller
{
    private ImageContext db = new ImageContext();
    private ProductContext pb = new ProductContext();

    //
    // GET: /JBI/Image/

    public ViewResult Index()
    {
        //attempt new things
        int id = 1;
        IEnumerable<Image> image = db.Image.TakeWhile(x => x.productID == id);
        IEnumerable<Product> product = pb.Product.TakeWhile(x => x.productID == id);

        ImageViewModel piViewModel = new ImageViewModel(image, product);
        return View(piViewModel);
        //return View(db.Image.ToList());
    }

    //
    // GET: /JBI/Image/Details/5

    public ViewResult Details(int id)
    {
        Image image = db.Image.Find(id);
        return View(image);
    }

    //
    // GET: /JBI/Image/Create

    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /JBI/Image/Create
    //this simply populates the DB values, but does not handle the file upload

    [HttpPost]
    public ActionResult Create(Image image)
    {
        if (ModelState.IsValid)
        {
            db.Image.Add(image);
            db.SaveChanges();
            return RedirectToAction("Index");  
        }

        return View(image);
    }

    [HttpPost]
    public ActionResult UploadFile(HttpPostedFileBase Filedata)
    {
        // Verify that the user selected a file
        if (Filedata != null && Filedata.ContentLength > 0)
        {
            // extract only the fielname
            var fileName = Path.GetFileName(Filedata.FileName);
            // store the file inside ~/App_Data/uploads folder
            var path = Path.Combine(Server.MapPath("~/Content/images/product/"), fileName);
            Filedata.SaveAs(path);
        }
        // redirect back to the index action to show the form once again
        return RedirectToAction("Index");
    }

    //
    // GET: /JBI/Image/Edit/5

    public ActionResult Edit(int id)
    {
        Image image = db.Image.Find(id);
        return View(image);
    }

    //
    // POST: /JBI/Image/Edit/5

    [HttpPost]
    public ActionResult Edit(Image image)
    {
        if (ModelState.IsValid)
        {
            db.Entry(image).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(image);
    }

    //
    // GET: /JBI/Image/Delete/5

    public ActionResult Delete(int id)
    {
        Image image = db.Image.Find(id);
        return View(image);
    }

    //
    // POST: /JBI/Image/Delete/5

    [HttpPost, ActionName("Delete")]
    public ActionResult DeleteConfirmed(int id)
    {            
        Image image = db.Image.Find(id);
        db.Image.Remove(image);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing)
    {
        db.Dispose();
        base.Dispose(disposing);
    }
}
}

ImageViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Web.Mvc;
using JustAdminIt.Areas.JBI.Models;

namespace JustAdminIt.Areas.JBI.ViewModels
{
public class ImageViewModel
{
    public IEnumerable<ImageViewModel> Image { get; set; }
    public IEnumerable<ImageViewModel> Product { get; set; }

    public ImageViewModel(IEnumerable<Image> image, IEnumerable<Product> product)
    {
        IEnumerable<Image> Image = image;
        IEnumerable<Product> Product = product;
    }
}
}

3 个答案:

答案 0 :(得分:1)

在您的索引操作方法中,您创建一个新的ImageViewModel(),然后将其传递给您的视图,但您的视图需要IEnumerable<ImageViewModel>

您正在做的是创建一个ImageViewModel,然后将两个集合传递给它。这就像使用一个盒子来容纳两组物品,而不是拥有一堆盒子,每个盒子容纳两个不同的物品中的一个。

您需要重新设计应用以正确方式生成项目。我不确定为什么你在这里有两个不同的数据上下文,但这会使事情复杂化很多。

答案 1 :(得分:1)

所以在阅读了大量资源之后,在@Mystere Man&amp;的帮助下,将代码“片段”脱离了上下文。 @Travis J我有解决方案。

首先,我正在为每个模型创建一个新的DbContext。我知道,愚蠢。所以这些都包含在他们自己的上下文文件中,我的web.config更加快乐。

示例DbContext在一个上下文中显示多个源:

public class MyDataContext : DbContext
{
    public DbSet<Bundle> Bundle { get; set; }
    public DbSet<Image> Image { get; set; }
    public DbSet<Product> Product { get; set; }
    public DbSet<Siteconfig> Siteconfig { get; set; }
}

更新的文件(仅发布已更改的文件,如果此处未列出,则与原始问题中的文件相同):

ImageViewModel.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Web.Mvc;
using JustAdminIt.Areas.JBI.Models;

namespace JustAdminIt.Areas.JBI.ViewModels
{
    public class ImageViewModel
    {
        public Image Image { get; set; }
        public Product Product { get; set; }
    }
}

ImageController.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using JustAdminIt.Areas.JBI.Models;
using JustAdminIt.Areas.JBI.ViewModels;
using JustAdminIt.Areas.JBI.DAL;
using System.IO;

namespace JustAdminIt.Areas.JBI.Controllers
{ 
public class ImageController : Controller
{
    //private ImageContext db = new ImageContext();
    //private ProductContext pb = new ProductContext();

    private JustBundleItContext db = new JustBundleItContext();

    //
    // GET: /JBI/Image/

    public ViewResult Index()
    {
        var model = from a in db.Product
                    join b in db.Image
                    on a.productID equals b.productID
                    select new ImageViewModel
                    {
                        Product = a,
                        Image = b
                    };
        return View(model.ToList());

    }

    //
    // GET: /JBI/Image/Details/5

    public ViewResult Details(int id)
    {
        Image image = db.Image.Find(id);
        return View(image);
    }

    //
    // GET: /JBI/Image/Create

    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /JBI/Image/Create
    //this simply populates the DB values, but does not handle the file upload

    [HttpPost]
    public ActionResult Create(Image image)
    {
        if (ModelState.IsValid)
        {
            db.Image.Add(image);
            db.SaveChanges();
            return RedirectToAction("Index");  
        }

        return View(image);
    }

    [HttpPost]
    public ActionResult UploadFile(HttpPostedFileBase Filedata)
    {
        // Verify that the user selected a file
        if (Filedata != null && Filedata.ContentLength > 0)
        {
            // extract only the fielname
            var fileName = Path.GetFileName(Filedata.FileName);
            // store the file inside ~/App_Data/uploads folder
            var path = Path.Combine(Server.MapPath("~/Content/images/product/"), fileName);
            Filedata.SaveAs(path);
        }
        // redirect back to the index action to show the form once again
        return RedirectToAction("Index");
    }

    //
    // GET: /JBI/Image/Edit/5

    public ActionResult Edit(int id)
    {
        Image image = db.Image.Find(id);
        return View(image);
    }

    //
    // POST: /JBI/Image/Edit/5

    [HttpPost]
    public ActionResult Edit(Image image)
    {
        if (ModelState.IsValid)
        {
            db.Entry(image).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(image);
    }

    //
    // GET: /JBI/Image/Delete/5

    public ActionResult Delete(int id)
    {
        Image image = db.Image.Find(id);
        return View(image);
    }

    //
    // POST: /JBI/Image/Delete/5

    [HttpPost, ActionName("Delete")]
    public ActionResult DeleteConfirmed(int id)
    {            
        Image image = db.Image.Find(id);
        db.Image.Remove(image);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing)
    {
        db.Dispose();
        base.Dispose(disposing);
    }
}
}

Index.cshtml

@model List<JustAdminIt.Areas.JBI.ViewModels.ImageViewModel>

@{
ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
    <th>
        Image Title
    </th>
    <th>
        Image Excerpt
    </th>
    <th>
        Image Description
    </th>
    <th>
        Image 
    </th>
    <th>
       Product ID
    </th>
    <th></th>
</tr>

@foreach (var item in Model) {

<tr>
    <td>
        @Html.DisplayFor(modelItem => item.Image.imageTitle)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Image.imageExcerpt)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Image.imageDescription)
    </td>
    <td>
        <img src="@Url.Content("~/Content/images/product/")@Html.DisplayFor(modelItem => item.Image.imageURL)" alt="Product Image" width="150" />
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Product.productName)
    </td>

    <td>
        @Html.ActionLink("Edit", "Edit", new { id = item.Image.imageID }) |
        @Html.ActionLink("Details", "Details", new { id = item.Image.imageID }) |
        @Html.ActionLink("Delete", "Delete", new { id = item.Image.imageID })
    </td>
</tr>
}

</table>

在控制器中使用LINQ查询允许我进行所需的连接,以查找与图像相关联的产品,同时大幅简化ViewModel。现在在视图中我可以选择item.Image组或item.Products组,知道它们已正确连接。

答案 2 :(得分:0)

问题可能是由于您使用了TakeWhile

“只要指定的条件为真,就返回序列中的元素,然后跳过剩余的元素。” - http://msdn.microsoft.com/en-us/library/system.linq.enumerable.takewhile.aspx

您可能希望Where使用db.Image.Where(x => x.productID == id).ToList(); pb.Product.Where(x => x.productID == id).ToList();

@model JustAdminIt.Areas.JBI.ViewModels.ImageViewModel

这只是其中的一部分。您正在传递一个包含这两个IEnumerable集的类。但是,您的视图正在接受该类的IEnumerable。你正确地传入,但没有正确接收。

@foreach (var item in Model) {

但是这里还有另一个问题。因为您的产品和图像在传递时不相关,所以不能同时在两者上使用foreach

@foreach (var item in Model.Product) {

可能是

{{1}}

但由于刚刚列出的原因,这并不意味着有尽可能多的图像。为了建立这种关系,你需要稍微重构一下。你应该如何实现这一目标。基本上,您需要在模型中创建虚拟关系,或者使用包含两者的类。