Search code examples
c#asp.net-mvclinqsubsonic

LINQ IQueryable


I have a Menu class that has a IQueryable property called WebPages. In the following statement I am returning Menu items based on a match but I need to include the Webpages property. Here is what I have at the moment.

var allCategories = Menu.All().Where(x => x.CategoryID == 4 && x.Visible)

I need to extend it to check a property in the WebPage class, something like this..

var allCategories = Menu.All().Where(x => x.CategoryID == 4 && x.Visible && x.WebPages.Roles.Contains(User.Identity.Name))

That won't compile but I hope you get the jist of what I am trying to do.

NOTE: The Webpage property is filled by the PageID not CategoryID but not sure if that makes a difference??

Here are a brief outline of my classes.

public partial class Menu: IActiveRecord
    {
       public int ID {get; set;}
       public int CategoryID {get;set;}
       public bool Visible {get;set;}
       public int PageID {get;set;}
       public IQueryable<WebPage> WebPages
        {
            get
            {

                  var repo=NorthCadburyWebsite.Models.WebPage.GetRepo();
                  return from items in repo.GetAll()
                       where items.ID == _PageID
                       select items;
            }
        }
}

public partial class WebPage: IActiveRecord
    {
       public int ID {get;set;}
       public string Roles {get;set;}
}

Solution

  • This should do it for you mate. You just need to say WebPages.Any, this will return true if any menus contain a webpage with your specified role.

    var allCategories = menus.Where(menu => menu.CategoryID == 1 && menu.Visible && menu.WebPages.Any(webPage => webPage.Roles.Contains(roleToSearchFor)));
    

    So the key bit that you need to add is this.

    menu.WebPages.Any(webPage => webPage.Roles.Contains(roleToSearchFor))
    

    Using the Any() function is very efficient as it will stop looking as soon as it finds a match.

    If you used Where() and then Count() it would iterate through all the Webpages to find all matches and then iterate through the results to count them, so that would be much less efficient.

    Below is a full source example for you to try.

        namespace DoctaJonez.TestingBrace
        {
            public partial class Menu //: IActiveRecord 
            { 
                public int ID { get; set; } 
                public int CategoryID { get; set; } 
                public bool Visible { get; set; } 
                public int PageID { get; set; } 
                public IQueryable<WebPage> WebPages { get; set; } 
            } 
    
            public partial class WebPage //: IActiveRecord 
            { public int ID { get; set; } public string Roles { get; set; } }
    
            public static class Launcher
            {
                /// <summary>
                /// The Main entry point of the program.
                /// </summary>
                static void Main(string[] args)
                {
                    Menu myMenu1 = new Menu
                    {
                        ID = 1,
                        CategoryID = 1,
                        PageID = 1,
                        Visible = true,
                        WebPages = new List<WebPage>()
                        {
                            new WebPage { ID = 1, Roles = "Role1" },
                            new WebPage { ID = 1, Roles = "Role2" },
                            new WebPage { ID = 1, Roles = "Role3" },
                        }.AsQueryable()
                    };
    
                    Menu myMenu2 = new Menu
                    {
                        ID = 1,
                        CategoryID = 1,
                        PageID = 1,
                        Visible = true,
                        WebPages = new List<WebPage>()
                        {
                            new WebPage { ID = 1, Roles = "Role3" },
                            new WebPage { ID = 1, Roles = "Role4" },
                            new WebPage { ID = 1, Roles = "Role5" },
                        }.AsQueryable()
                    };
    
                    Menu myMenu3 = new Menu
                    {
                        ID = 1,
                        CategoryID = 1,
                        PageID = 1,
                        Visible = true,
                        WebPages = new List<WebPage>()
                        {
                            new WebPage { ID = 1, Roles = "Role5" },
                            new WebPage { ID = 1, Roles = "Role6" },
                            new WebPage { ID = 1, Roles = "Role7" },
                        }.AsQueryable()
                    };
    
                    List<Menu> menus = new List<Menu>() { myMenu1, myMenu2, myMenu3 };
    
                    string roleToSearchFor = "Role3";
    
                    var allCategories = menus.Where(menu => menu.CategoryID == 1 && menu.Visible && menu.WebPages.Any(webPage => webPage.Roles.Contains(roleToSearchFor))).ToList();
    
                    return;
                }
            }