title: Asp.Net Mvc hierarchical categories self-related with One-To-Many
body: <p>I'm trying to create category tree. With this purpose i created some classes. I done somethings let me show you what i did and whats gone wrong.</p>
  
  <p>I created a self-referenced model like below.</p>
  
  <pre><code>public class Category 
  {
      public int Id { get; set; }
      public string Title { get; set; }
      public bool Published { get; set; }
  
      public int? ParentId { get; set; }
      public virtual Category RootCategory { get; set; }
      public virtual ICollection&lt;Category&gt; SubCategories { get; set; }
  }
  </code></pre>
  
  <p>and i mapped it like below</p>
  
  <pre><code>public class CategoryMap : EntityTypeConfiguration&lt;Category&gt;
  {
      public CategoryMap()
      {
          // Primary Key
          this.HasKey(t =&gt; t.Id);
          // Properties
          this.Property(t =&gt; t.Title)
              .IsRequired()
              .HasMaxLength(150);
          this.Property(t =&gt; t.Published)
              .IsRequired();
          // Table &amp; Column Mappings
          this.ToTable("Category");
          this.Property(t =&gt; t.Id).HasColumnName("Id");
          this.Property(t =&gt; t.Title).HasColumnName("Title");
          this.Property(t =&gt; t.Published).HasColumnName("Published");
          HasOptional(x =&gt; x.RootCategory).WithMany(x =&gt; x.SubCategories).HasForeignKey(x =&gt; x.ParentId).WillCascadeOnDelete(false);
      }
  }
  </code></pre>
  
  <p>To Create and Edit Category i created a ViewModel like below</p>
  
  <pre><code>public class CreateEditCategoryViewModel
  {
      [HiddenInput]
      public int Id { get; set; }
      [Required]
      public string Title { get; set; }
      public bool Published { get; set; }
  
      private int? _selectedCategory;
      public int? SelectedCategory
      {
          get { return _selectedCategory; }
          set { _selectedCategory = value; }
      }
  }
  </code></pre>
  
  <p>Here is my Controller Create action</p>
  
  <pre><code>    [HttpPost]
      [ValidateAntiForgeryToken]
      public ActionResult Create(CreateEditCategoryViewModel viewModel)
      {
          if (ModelState.IsValid)
          {
              Category category = new Category();
  
              if (viewModel.SelectedCategory &gt; 0)
              {
                  category.ParentId = viewModel.SelectedCategory;
              }
  
              category.Title = viewModel.Title;
              category.Published = viewModel.Published;
  
              db.Categories.Add(category);
              db.SaveChanges();
              return RedirectToAction("Index");
  
          }
  
          ViewBag.SelectedCategory = new SelectList(db.Categories, "Id", "Title", viewModel.SelectedCategory);
          return View(viewModel);
      }
  </code></pre>
  
  <p>Here is my Create view,</p>
  
  <pre><code>    @model BiSahne.Areas.Administrator.Models.CreateEditCategoryViewModel
  
  &lt;div id="inputs" class="box g8"&gt;
      &lt;h2 class="box-ttl"&gt;Category Ekle&lt;/h2&gt;
      &lt;div class="box-body form"&gt;
          @Html.LabelFor(model =&gt; model.Title, new { @class = "label input g4" })
          @Html.TextBoxFor(model =&gt; model.Title, new { @class = "g12" })
          @Html.ValidationMessageFor(model =&gt; model.Title)
  
          &lt;span class="label g4"&gt;Published&lt;/span&gt;
          @Html.CheckBoxFor(model =&gt; model.Published, new { @class = "g1" })
  
          &lt;button type="submit" class="green btn-m flt-r g3"&gt;Kaydet&lt;/button&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  
  &lt;div class="box coll g8" style="height: 500px"&gt;
      &lt;div class="box-body form"&gt;
          &lt;span class="label g16"&gt;Categories&lt;/span&gt;
          &lt;hr /&gt;
          &lt;select size="20" title="Select Category" name="SelectedCategory" class="form-control select" data-live-search="true"&gt;
  
              @foreach (BiSahne.Models.Content.Category item in ViewBag.SelectedCategory)
              {
  
                  if (item.RootCategory == null) //top level
                  {
                      &lt;option value="@item.Id"&gt;@item.Title&lt;/option&gt;
  
                      foreach (var item2 in item.SubCategories)
                      {
                          &lt;option value="@item2.Id"&gt;---@item2.Title&lt;/option&gt;
                          if (item2.SubCategories.Count &gt; 0)
                          {
                              foreach (var item3 in item2.SubCategories)
                              {
                                  &lt;option value="@item3.Id"&gt;------@item3.Title&lt;/option&gt;
                                  if (item3.SubCategories.Count &gt; 0)
                                  {
                                      foreach (var item4 in item3.SubCategories)
                                      {
                                          &lt;option value="@item4.Id"&gt;------@item4.Title&lt;/option&gt;
                                          if (item4.SubCategories.Count &gt; 0)
                                          {
                                              foreach (var item5 in item4.SubCategories)
                                              {
                                                  &lt;option value="@item5.Id"&gt;------@item5.Title&lt;/option&gt;
                                              }
                                          }
                                      }
                                  }
                              }
                          }
                      }
                  }
  
              }
          &lt;/select&gt;
  
      &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>}</p>
  
  <p>This is my Edit action method.</p>
  
  <pre><code>    public ActionResult Edit(int? id)
      {
          if (id == null)
          {
              return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
          }
          Category category = db.Categories.Find(id);
  
          if (category == null)
          {
              return HttpNotFound();
          }
  
          CreateEditCategoryViewModel viewModel = new CreateEditCategoryViewModel()
          {
              Id = category.Id,
              Title = category.Title,
              Published = category.Published,
          };
  
  
          ViewBag.SelectedCategory = new SelectList(db.Categories, "Id", "Title", viewModel.SelectedCategory);
          return View(viewModel);
      }
  </code></pre>
  
  <blockquote>
    <p>Edit.cshtml view same as Create.cshtml view above.</p>
  </blockquote>
  
  <p>I can create category and i can assign a parent for it. But when i'm trying to edit the category -and also when Create Action returns view due to ModelState is not valid- i'm getting error like below</p>
  
  <pre><code>An exception of type 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' occurred in System.Core.dll but was not handled in user code. Additional information: Cannot convert type 'System.Web.Mvc.SelectListItem' to 'BiSahne.Models.Content.Category'
  </code></pre>
  
  <p>Pointed to this line in edit.cshtml</p>
  
  <pre><code>                @foreach (BiSahne.Models.Content.Category item in ViewBag.SelectedCategory)
              {
  </code></pre>
  
  <p>How can i fix that problem? I have to list categories and select the selected category.</p>