2015-10-29 17 views
3

我們正在製作一個像https://www.etsy.com/這樣的市場。我們在分類列表時遇到問題。我們希望類別3級上市的項目,f.ex它必須是在這個訂單類別:在asp.net mvc分類/子類別

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等...

+0

如果您使用的是SQL Server,那麼您應該嘗試使用HIERARCHYID DataType:https://msdn.microsoft.com/en-us/library/bb677213.aspx – Hackerman

+0

@Hackerman:不幸的是,實體框架不支持此處的hierarchyid時間。儘管OP沒有明確提到EF或標記問題,但IdentityDbContext的存在意味着EF正在使用中。 –

+0

@ChrisPratt,是的,但我的意思是,爲什麼不讓sql服務器處理所有這些邏輯,並將EF與存儲過程一起用於此場景? – Hackerman

回答

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屬性即可顯示子類別。

UPDATE

如果您需要完整的層次,而不是在同一時間只有一個級別,你有兩個選擇。首先,你可以查詢時只包括多個層次:

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

這並不是高效的,不過,我肯定不會推薦鑽研比三級兒童深刻得多。然而,這就是你所要求的,所以這仍然是一個可行的方法。

其次,您可以創建一個存儲過程來爲您分層結構。它稍微複雜一點,但是結合使用WITHUNION ALL,您可以創建層次結構的平面表示,然後遞歸使用LINQ的GroupBy將其重新構建爲層次結構。

@ Hackerman推薦使用HIERARCHYID的最後一種潛在的第三種選擇,但不幸的是,您必須從EF上下文中完全刪除Category,這也意味着刪除了與它的任何直接關係。要將產品關聯到某個類別,只能存儲該id(不作爲外鍵),然後使用該id在第二步中手動查找該類別。不幸的是,儘管這個解決方案使處理層次結構變得更容易,但它使其他事情變得更加困難。無論如何,這取決於你。

+0

感謝您的回答。我們是這個框架的初學者,並且有一些問題。 1.公共類Mapping:EntityTypeConfiguration ----類必須在Category類中? 2.你是指公共類Mapping()還是公共類Mapping() 3。你把OnModelCreating方法放在哪裏?它在ApplicationDbContext中:IdentityDbContext ---類? (db.Categories.Include(「Children.Children」)); - 放在控制器中? –

+0

配置不與實體在一起,但最好遵循這個習慣,因爲它將實體和配置保存在同一個地方。是的,它應該是一個班級。在類中定義的類本質上就像一個靜態方法,因爲您不必新建包含類來獲取它。它只是提供一個名稱空間,並將所有內容保持在一起。是的,OnModelCreating方法進入你的上下文,並且Include調用進入控制器。 –

0

這似乎是一個正確的解決方案。

對於所有類別,您也只能使用一個類(一個數據庫表等)。您的「類別」類/表必須包含父類別的參考(可爲空)。這允許爲所有類別進行通用處理。

例如,當用戶創建項目時,可以顯示主類別的下拉列表。如果用戶選擇包含其他類別的類別,則會顯示其他下拉列表以及子類別等...

+0

謝謝。這正是我們試圖做的事情(基於類別/子類別的3個下拉菜單)。你有任何代碼片段/鏈接/良好的建議如何玩這個?我想現在我們有一個好主意,如何製作模型並將其正確保存在數據庫中。但如何在視圖中顯示它是一個問題。 –

+0

最簡單的解決方案可能是創建一個具有所有元素的唯一下拉列表(顯示爲樹)。如果要實施3個下拉列表解決方案,則可以在產品模型中創建3個「類別」屬性,生成3個drodpownlists,但僅顯示第一個。然後在第一個下拉更改事件上綁定一個JavaScript方法,該方法啓動一個AJAX請求以加載第二個下拉列表的內容等。您可以優化代碼以使其只有一個控制器方法和一個JavaScript方法:http:/ /jsfiddle.net/vwh32hvj/(不工作,只是爲了解釋我的解決方案)。 –

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>