【问题标题】:How do I make a foreign key display only once in @foreach in MVC 5如何在 MVC 5 的 @foreach 中只显示一次外键
【发布时间】:2014-07-10 23:29:43
【问题描述】:

我有一个项目(如下),其中有类别和产品。每个类别都有多个产品,从模型中可以看出,类别 ID 被引用为外键。我想要做的是让每个类别显示为一个 div,相应的产品显示在下面的无序列表中。使用我拥有的代码,我不断得到一个 div 和一个产品,每个产品的类别都重复。

我已经搜索和搜索,但似乎无法找到解决方案。我哪里错了?

视图模型

使用系统; 使用 System.Collections.Generic; 使用 System.ComponentModel.DataAnnotations; 使用 System.ComponentModel.DataAnnotations.Schema; 使用 System.Linq; 使用 System.Web; 使用 System.Web.Mvc;
namespace WebApplication1.Web.Models
{
public class Category
{
    public int CategoryID { get; set; }

    [Required, Display(Name = "Category Name")]
    public string CategoryName { get; set; }

    public bool IsDisplayedInMainMenu { get; set; }
}

public class Product
{
    public int ProductID { get; set; }

    public int CategoryID { get; set; }

    [ForeignKey("CategoryID")]
    [Display(Name = "Category Name")]
    public Category CategoryName { get; set; }

    [Required, Display(Name = "Product Name")]
    public string ProductName { get; set; }

    [Required, Display(Name = "Product Description")]
    [DataType(DataType.MultilineText)]
    public string ProductDescription { get; set; }
}
}

产品控制器

namespace WebApplication1.Controllers
{
public class ProductsController : Controller
{
    private ServiceContext db = new ServiceContext();
    // GET: Products
    public ActionResult Index()
    {
        var products = db.Products.Include(p => p.CategoryName);
        return View(products.ToList());
    }
}
}

查看 model IEnumerable

@{
ViewBag.Title = "Products";
}

<h2>@ViewBag.Title</h2>

<div class="row">
@foreach (var item in Model)
{
    <div class="col-md-3">
        <h4><strong>@item.CategoryName.CategoryName</strong></h4>
    <ul class="list-unstyled">
        @if (item.ProductName.Any())
        {
            <li>
                    @item.ProductName
            </li>
        }
    </ul>
    </div>
}
</div>

产品

木材 2×4

木材 1 X 4

木材 胶合板

电动工具 钻孔

电动工具 圆锯

花园 柠檬树

花园 橘子树

紧固件 干墙螺丝

紧固件 甲板螺丝

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-5.1


    【解决方案1】:

    更改您发送到视图的数据。而不是 this.DB.Products...尝试以下操作:

    return this.View(this.DB.Category.Select(x => new { CategoryName = x.CategoryName, Products = x.Products);
    

    ...或类似的东西,具体取决于您的数据库结构。这个想法是有一个类似于您实际想要在视图中显示的模型。这通常称为视图模型。

    public class CategoryViewModel
    {
        public string CategoryName {get; set;}
        public IEnumerable<Product> Products {get; set;}
    }
    

    如果你有这样一个类,那么你的控制器方法可能如下所示:

    return this.View(this.DB.Category.Select(x => new CategoryViewModel { CategoryName = x.CategoryName, Products = x.Products));
    

    那么在你看来:

    <div class="col-md-3">
    <h4><strong>@Model.CategoryName</strong></h4>
    @foreach (var item in Model.Products)
    {
        <ul class="list-unstyled">
            @item.ProductName (or something)
        </ul>
    }
    </div>
    

    我不在开发机器上,所以我真的无法判断我是否打错了。不过,我很乐意回答您的任何问题。

    【讨论】:

    • 感谢您的快速回复。所以我创建了 ViewModel 并进行了其他建议的更改。现在我收到以下错误:在模型生成期间检测到一个或多个验证错误:WebApplication1.Context.CategoryViewModel: : EntityType 'CategoryViewModel' has no key defined。定义此 EntityType 的键。 CategoryViewModel: EntityType: EntitySet 'CategoryViewModel' 基于没有定义键的类型'CategoryViewModel'。
    • 另外,有没有一种基于我上面的理论的方法,也可以动态地为类别创建第一个 div?换句话说,为每个 Category 创建一个 div,并为相应的产品创建一个 li。
    • 听起来您试图在 DbContext 中使用 CategoryViewModel 作为 DbSet。它应该是 DbSet 并且您的类别应该有一个 int Id 或 int CategoryId 的主键。视图模型的想法是成为视图所需的属性的简单集合,这些属性恰好对应于您的一个实体。因此,可以从数据库中检索实体作为类别,创建一个新的 CategoryViewModel,将属性从 Category 复制到新的 CategoryViewModel 并将视图模型发送到视图。有意义吗?
    【解决方案2】:

    如果您要退回选定类别下的产品,您可以使用以下代码

    @if(Model.Count()>0)
    {
       <h4><strong>@Model.ToList()[0].CategoryName.CategoryName</strong></h4>
    }
    

    希望能成功

    【讨论】:

    • 推荐使用 Model.Any() 而不是 Model.Count()>0。对于大型数据集来说效率更高,因为 .Any() 会在找到任何内容之一时停止, .Count() 会计算所有记录
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多