2

I'm trying to transform this Tutorial to read the data from a table. I have modified the NavigationMenu.cs Models by adding an Id key field:

public class NavigationMenu
{

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Text { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }
    public string Icon { get; set; }
    public bool Selected { get; set; }

    public List<NavigationMenu> MenuChildren;

}

added a Context:

public class NavigationMenuContext : DbContext
{

    public NavigationMenuContext() : base("name=DefaultConnection")  
    {
    }

    public DbSet<NavigationMenu> NavigationMenus { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        base.OnModelCreating(modelBuilder);
    }
}

and modified the specific controller:

public class NavigationController : Controller
{

    // GET: NewMenu
    public ActionResult Index()
    {
        NavigationMenuContext navigationMenuContext = new NavigationMenuContext();
        List<NavigationMenu> menuItems = navigationMenuContext.NavigationMenus.ToList();
        return View(menuItems);
    }       

    [ChildActionOnly]
    public ActionResult GenerateMenu()
    {

        NavigationMenuContext navigationMenuContext = new NavigationMenuContext();
        List<NavigationMenu> menuItems = navigationMenuContext.NavigationMenus.ToList();

        string action = ControllerContext.ParentActionViewContext.RouteData.Values["action"].ToString() == "Index" ? "" : ControllerContext.ParentActionViewContext.RouteData.Values["action"].ToString();
        string controller = ControllerContext.ParentActionViewContext.RouteData.Values["controller"].ToString();

        foreach (var item in menuItems)
        {
            if (item.MenuChildren != null)
            {
                foreach (var cItem in item.MenuChildren)
                {
                    if (cItem.Controller == controller && cItem.Action == action)
                    {
                        cItem.Selected = true;
                        break;
                    }
                    else
                    {
                        cItem.Selected = false;
                    }
                }
            }
            if (item.Controller == controller && item.Action == action)
            {
                item.Selected = true;
                break;
            }
            else
            {
                item.Selected = false;
            }
        }

        return PartialView("~/Views/Shared/_Navigation.cshtml", menuItems);
    }

}

But I am not able to get the same result with the second level menu: NavigationMenus Table

How to modify the code to render tehe second level menù in the view?

Community
  • 1
  • 1
max
  • 35
  • 6
  • How MenuChildren property is being populated? In the database table all the menu items looks at the same level? How are they having parent child relationship? You should have a parentMenuId column in the table which will indicate who is the parent menuitem. If parentMenuId is 0 or null then that can be considered as the top level menu. Also you need to change you EF binding changed to support One-Many relationship. – Chetan Jan 20 '17 at 12:17
  • please check my answer hope it will help you – Yashveer Singh Jan 20 '17 at 13:07

1 Answers1

0
Hi this is the  way you can achive what you want to do . I just added a line on OnMidelCreating and then testted the code woith 

  var result = context.MaineMenu.ToList(); // here I gold child menus in the list 


public class NavigationMenuContext : DbContext
{

public NavigationMenuContext() : base("name=DefaultConnection")  
{
}

public DbSet<NavigationMenu> NavigationMenus { get; set; }

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
    -- this is changed -- 
    modelBuilder.Entity<NavigationMenu>().HasMany(c => c.MenuChildren);
 }
}

--- after this when I add a new Migration the migrations looks like this . see new Id column and foreign key has been added by EF.

public override void Up()
    {
        CreateTable(
            "dbo.NavigationMenus",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Text = c.String(),
                    Action = c.String(),
                    Controller = c.String(),
                    Icon = c.String(),
                    Selected = c.Boolean(nullable: false),
                    NavigationMenu_Id = c.Int(),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.NavigationMenus", t => t.NavigationMenu_Id)
            .Index(t => t.NavigationMenu_Id);

    }

    public override void Down()
    {
        DropForeignKey("dbo.NavigationMenus", "NavigationMenu_Id", "dbo.NavigationMenus");
        DropIndex("dbo.NavigationMenus", new[] { "NavigationMenu_Id" });
        DropTable("dbo.NavigationMenus");
    }

data in SQL server and output from application

enter image description here

Classes -----

    public class SampleDbContext : DbContext
    {
        public SampleDbContext()
            : base("name=SampleDBConnection")
        {
            this.Configuration.LazyLoadingEnabled = false;
        }



        public DbSet<NavigationMenu> MaineMenu { get; set; }



        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Candidate>().HasMany(t => t.SkillSets).WithMany(t => t.Candidates)
                .Map(m =>
                {
                    m.ToTable("candidate_skillset");
                    m.MapLeftKey("candidate_id");
                    m.MapRightKey("skillset_id");
                });

            modelBuilder.Entity<SkillSet>().ToTable("skillset");
            modelBuilder.Entity<Candidate>().ToTable("candidate");

            modelBuilder.Entity<NavigationMenu>().HasMany(c => c.MenuChildren);



        }
    }


    public class NavigationMenu
    {

        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        public NavigationMenu()
        {
            MenuChildren = new Collection<NavigationMenu>();
        }

        public string Text { get; set; }
        public string Action { get; set; }
        public string Controller { get; set; }
        public string Icon { get; set; }
        public bool Selected { get; set; }


        public ICollection<NavigationMenu> MenuChildren { get; set; }

    }
Yashveer Singh
  • 1,914
  • 2
  • 15
  • 23
  • How the MenuChidren property will initialize from database? Looking at the table structure shared by user there is no way that MenuChidren will have any item in it. – Chetan Jan 20 '17 at 13:17
  • hi @ChetanRanpariya when I add that line in modelbuilder then EF automaticaly created a ID which is then created as foriegnkey on the table this way you can read the child of particlar id . – Yashveer Singh Jan 20 '17 at 13:20
  • @ChetanRanpariya added my Migration after this change have a look . I am going to add table data and result on a console application . – Yashveer Singh Jan 20 '17 at 13:23
  • @ChetanRanpariya check updated answer with data and application output . I hope you like it. – Yashveer Singh Jan 20 '17 at 13:30
  • @ChetanRanpariya we can add that foreign key in the main class so that we can set the parent menu of child sub menu . EF created it automatically but we have option to declare that in our DBSet class . I didn't showed that part as the question was about how to create model and retrieve data . – Yashveer Singh Jan 20 '17 at 13:39
  • Very well makes sense now. – Chetan Jan 20 '17 at 14:03
  • @ChetanRanpariya thanks . Lets see if I get upvote from the person waiting for his reply :) – Yashveer Singh Jan 20 '17 at 14:05
  • I have an error: The expression 'c => c.MenuChildren' is not a valid property expression. The expression should represent a property: C#: 't => t.MyProperty' – max Jan 20 '17 at 14:22
  • Can you please use my DBContext class and other entity class please . I tested it with a nre application and it is working fine . let me know if you have issues with the classes that I pasted above – Yashveer Singh Jan 20 '17 at 14:42
  • @max Updated the answer to include model class and DbContext class – Yashveer Singh Jan 20 '17 at 14:44
  • @Yashveer thanks but I prefer the Chetan solution with the foreign keys to same table. I don't undestand how to implement that way in the NavigationMenu.cs Model – max Jan 20 '17 at 15:38
  • And what is different here ? in my solution I have FK to same table . Have you looked into my answer ? It contains a FK to same table Also I shared you the screenshot so not able to understand what is the difference . Also i think @ChetanRanpariya can share his thoughts. – Yashveer Singh Jan 20 '17 at 15:42
  • @max in my table ParentId is Id and NavigationMenu_Id refer to parent of the child . So this is what you want FK in both table and my answer has all this.\ – Yashveer Singh Jan 20 '17 at 15:48
  • Excuse me Yashever i've made a bit of confusion with the name :) You give me the right solution, I undestand the solution via screenshot but not via code: "candidate_skillset" is the name of my table (NavigationMenu)? I'm a bit confused with m.MapLeftKey("candidate_id") and m.MapRightKey("skillset_id"), are the Id and NavigationMenu_id field? Thanks for your patience – max Jan 20 '17 at 16:34
  • @max not an Issues if you are happy with answer this is needed .please accept and like it if it is useful to you, – Yashveer Singh Jan 20 '17 at 16:38
  • @max nice question anyway so upvoted your question :) – Yashveer Singh Jan 20 '17 at 17:53