asp.net中的分类/子类别mvc

时间:2015-10-29 13:20:50

标签: asp.net-mvc

我们正在创建像https://www.etsy.com/这样的市场。我们在列表分类方面存在问题。我们希望将列表中的项目分为3个级别,f.ex必须按此顺序分类:

 Category 1 
    Sub Category 1.1
       Sub Category 1.1.1

重要的一点是,当你选择一个类别时,f.ex。电子产品,然后在子类别中,你只能看到电脑,智能手机,电视等东西。

这就是我们现在所拥有的

 public class Listing
{
    public int ListingId { get; set; }
    public String Name { get; set; }

    public int Subcategory2Id { get; set; }
    public virtual Subcategory2 Subcategory2 { get; set; }
}



public class Category
{
    public int CategoryId { get; set; }
    public String CategoryName { get; set; }

    public virtual ICollection<Subcategory1> Subcategory1s { get; set; }
}



public class Subcategory1
{
    public int Subcategory1Id { get; set; }
    public String Subcategory1Name { get; set; }

    public int CategoryId { get; set; }
    public virtual Category Categories { get; set; }

    public virtual ICollection<Subcategory2> Subcategory2s { get; set; }
}



public class Subcategory2
{
    public int Subcategory2Id { get; set; }
    public String Subcategory2Name { get; set; }

    public int Subcategory1Id { get; set; }
    public virtual Subcategory1 Subcategory1s { get; set; }

    public virtual ICollection<Listing> Listings { get; set; }
}

在IdentityModels-ApplicationDbContext中我们有

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public DbSet<Listing> Listings { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Subcategory1> Subcategory1s { get; set; }
    public DbSet<Subcategory2> Subcategory2s { get; set; }

    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

事情是我们不确定这是他正确的做法,我们不知道如何继续,这意味着当你创建一个列表时,你必须有3个下拉列表,你在哪里选择相应的类别。首先,您选择您的类别,然后您可以选择子类别1等...

3 个答案:

答案 0 :(得分:4)

您绝对不应该有多个类别/子类别实体。一个类别可以有一个父类,它可以有子元素,但它们都是“类别”。

public class Category
{
    public int Id { get; set; }

    public int? ParentId { get; set; }
    public virtual Category Parent { get; set; }

    public virtual ICollection<Category> Children { get; set; }
}

ParentId可以为空,因为顶级类别没有父级。

实体框架往往会被自引用关系弄糊涂,因此您可能需要一些流畅的配置来帮助它:

public class Category
{
    // properties

    public class Mapping : EntityTypeConfiguration<Category>
    {
        public class Mapping()
        {
            HasOptional(m => m.Parent).WithMany(m => m.Children);
        }
    }
}

然后,在你的背景下:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new Category.Mapping());
}

完成所有这些后,当您处于“电子”类别时,只需迭代它的Children属性即可显示子类别。

<强>更新

如果您需要完整的层次结构而不是一次只需一个级别,那么您有几个选择。首先,您可以在查询时包含多个级别:

db.Categories.Include("Children.Children");

但这并不是很有效率,我绝对不会建议比三级儿童更深入地钻研。但是,这就是你所要求的,所以这仍然是一种可行的方法。

其次,您可以创建一个存储过程来为您遍历层次结构。它有点复杂,但是通过WITHUNION ALL的组合,您可以创建层次结构的平面表示,然后递归使用LINQ的GroupBy将其重新分解为层次结构

@ Hackerman建议使用HIERARCHYID的最后一个潜在的第三个选项,但不幸的是,要做到这一点,你必须从EF上下文中完全删除Category,这也意味着删除与它的任何直接关系,以及。要将产品与类别相关联,您只能存储id(而不是外键),然后使用该id在第二步中手动查找类别。不幸的是,虽然这个解决方案使得更容易处理层次结构,但它使其他一切变得更加困难。无论哪种方式,都取决于你。

答案 1 :(得分:0)

这似乎是一个正确的解决方案。

您也可以只为所有类别使用一个类(一个DB表等)。然后,您的“类别”类/表必须包含父类别的引用(可为空)。这允许对所有类别进行通用处理。

例如,当用户创建项目时,您可以显示主类别的下拉列表。如果用户选择包含其他类别的类别,则会显示包含子类别等的其他下拉列表...

答案 2 :(得分:0)

我在这里给出了一个带图像上传的类别和子类别的例子。

 public class ProductController : Controller
{
    ApplicationDbContext db = new ApplicationDbContext();
    // GET: Product
    public ActionResult Index()
    {

        return View();
    }

    public ActionResult insert(int? id)
    {
        ViewBag.categoryList = db.Product.Where(x => x.CategoryId == 0).Select(x => new SelectListItem { Text = x.name, Value = x.Id.ToString() }).ToList();
        var product = db.Product.Where(x => x.Id == id).Select(x => x).FirstOrDefault();
        if (product == null) { product = new Product(); product.CategoryId = 0; }
        return View(product);
    }
    [HttpPost]
    public ActionResult insert(Product model)
    {

        if (Request.Files.Count > 0)
            if (Request.Files["fileupload"].ContentLength > 0)
            {
                var fileupload = Request.Files[0];
                var fileName = Path.GetFileName(fileupload.FileName);
                model.Imagename = fileName;
                model.ImageUrl = DateTime.Now.Ticks.ToString() + "." + fileName.Split('.')[1];

                string baseurl = Server.MapPath("/") + "Images/" + model.ImageUrl;
                fileupload.SaveAs(baseurl);
            }
        if (model.Id > 0)
        {
            var productEntity = db.Product.Where(x => x.Id == model.Id).Select(x => x).FirstOrDefault();
            if (model.Imagename != null)
                productEntity.Imagename = model.Imagename;
            if (model.ImageUrl != null)
                productEntity.ImageUrl = model.ImageUrl;
            productEntity.name = model.name;
            productEntity.CategoryId = model.CategoryId;
        }
        else
        {
            db.Product.Add(model);
        }
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    public ActionResult ProductList()
    {
        var product = db.Product.Where(x => x.Id > 0).Select(x => x).ToList();
        return View(product);
    }

    public ActionResult getsubcategory(int id)
    {
        var list = db.Product.Where(x => x.CategoryId == id)
                     .Select(x => new SelectListItem { Text = x.name, Value = x.Id.ToString() }).ToList();
        return Json(list, JsonRequestBehavior.AllowGet);
    }

}

此上层控制器用于插入更新记录。

html代码:

                @model WebApplication1.Models.Product

            @{
                ViewBag.Title = "insert";
                Layout = "~/Views/Shared/_Layout.cshtml";
            }

            <h2>insert</h2>

            @using (Html.BeginForm("insert","product", FormMethod.Post,new { enctype = "multipart/form-data" }))
            {
                @Html.AntiForgeryToken()

                <div class="form-horizontal">
                    <h4>Product</h4>
                    <hr />
                    @Html.HiddenFor(x=>x.Id)
                    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                    <div class="form-group">
                        <label class="control-label col-md-2">SubCategory</label>
                        <div class="col-md-10">
                            @Html.DropDownList("SubCategory", new SelectList(ViewBag.categoryList, "Value", "Text", Model.CategoryId), "-Select-", new { @onchange = "categoryselect()", htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.CategoryId, "", new { @class = "text-danger" })
                        </div>
                    </div>
                    <div class="form-group">
                        @Html.LabelFor(model => model.CategoryId, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">

                            @Html.DropDownListFor(model => model.CategoryId, new SelectList(ViewBag.categoryList, "Value", "Text", Model.CategoryId),"-Select-", new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.CategoryId, "", new { @class = "text-danger" })
                        </div>
                    </div>


                    <div class="form-group">
                        @Html.LabelFor(model => model.name, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            @Html.TextBoxFor(model => model.name, new { htmlAttributes = new { @class = "form-control" } })
                            @Html.ValidationMessageFor(model => model.name, "", new { @class = "text-danger" })
                        </div>
                    </div>


                    <div class="form-group">
                        @Html.LabelFor(model => model.Imagename, htmlAttributes: new { @class = "control-label col-md-2" })
                        <div class="col-md-10">
                            <input id="Imagename" name="fileupload" type="file" class = "form-control"  />
                            @*@Html.(model => model.Imagename, new { htmlAttributes = new { @class = "form-control" } })*@
                            @Html.ValidationMessageFor(model => model.Imagename, "", new { @class = "text-danger" })
                        </div>
                    </div>

                    <div class="form-group">
                        <div class="col-md-offset-2 col-md-10">
                            <input type="submit" value="Create" class="btn btn-default" />
                        </div>
                    </div>
                </div>
            }

            <div>
                @Html.ActionLink("Back to List", "Index")
            </div>
            <script>

                function categoryselect () {

                    var d = $("#SubCategory option:selected").val();
                    $.ajax({
                        url: "/product/getsubcategory?id="+d
                    , type: "get"
                        , success: function (data) {

                            // alert(data)
                            $("#CategoryId").html('<option value="">-select- </option>');
                            for(var i=0;i<data.length;i++)
                                $("#CategoryId").append('<option value="' + data[i].Value + '">' + data[i].Text + '</option>')
                        }
                    })

                    } 
            </script>

模型:

                namespace WebApplication1.Models
            {
                public class Product
                {
                    [Key]
                    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
                    public int Id { get; set; }
                    public int CategoryId { get; set; }
                    public string name { get; set; }
                    public string ImageUrl { get; set; }
                    public string Imagename { get; set; }
                }

                public class Category
                {
                    [Key]
                    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
                    public int Id { get; set; }
                    public int PrentId { get; set; }
                    public string name { get; set; }

                }
            }

索引页:

                @{
                ViewBag.Title = "Index";
                Layout = "~/Views/Shared/_Layout.cshtml";
            }

            <h2>Index</h2>

            <div id="productList">

            </div>
            <script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>

            <script>
                $(document).ready(function () {
                    $.ajax({
                        url:"/product/productlist"
                        , type: "GET"
                        ,success:function(data)
                        {
                            $("#productList").html(data)
                        }
                    })

                })
            </script>

列表页面:

                @model IEnumerable<WebApplication1.Models.Product>

            <p>
                @Html.ActionLink("Create New", "Insert")
            </p>
            <table class="table">
                <tr>
                    <th>
                        @Html.DisplayNameFor(model => model.CategoryId)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.name)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.ImageUrl)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.Imagename)
                    </th>
                    <th></th>
                </tr>

            @foreach (var item in Model) {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.CategoryId)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.name)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.ImageUrl)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Imagename)
                    </td>
                    <td>
                        @Html.ActionLink("Edit", "insert", new { id=item.Id }) 

                    </td>
                </tr>
            }

            </table>