首页 文章

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

提问于
浏览
2

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

我有一个视图,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

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

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

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

  • 1

    因此,在阅读了大量资源之后,在@Mystere Man和@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组,知道它们已正确连接 .

  • 1

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

    "Returns elements from a sequence as long as a specified condition is true, and then skips the remaining elements." - http://msdn.microsoft.com/en-us/library/system.linq.enumerable.takewhile.aspx

    你可能想在那里使用 Wherehttps://stackoverflow.com/a/5031771/1026459

    db.Image.Where(x => x.productID == id).ToList();
    pb.Product.Where(x => x.productID == id).ToList();
    

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

    @model JustAdminIt.Areas.JBI.ViewModels.ImageViewModel
    

    但是这里还有另一个问题 . 由于您的产品和图像在传递时不相关,因此您无法同时使用foreach

    @foreach (var item in Model) {
    

    可能

    @foreach (var item in Model.Product) {
    

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

相关问题