【问题标题】:LINQ IQueryableLINQ 可查询
【发布时间】:2009-06-24 10:13:19
【问题描述】:

我有一个 Menu 类,它有一个名为 WebPages 的 IQueryable 属性。在以下语句中,我根据匹配返回菜单项,但我需要包含 Webpages 属性。这是我目前拥有的。

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

我需要扩展它来检查 WebPage 类中的一个属性,像这样..

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

这不会编译,但我希望你能明白我正在尝试做的事情。

注意:网页属性由 PageID 而非 CategoryID 填充,但不确定这是否有区别??

这是我的课程的简要概述。

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;}
}

【问题讨论】:

    标签: c# asp.net-mvc linq subsonic


    【解决方案1】:

    如果我正确理解了这个问题,你想要这样的东西:

    var menuItems =
        from menuItem in Menu.All()
            where menuItem.Visible
                and (
                    menuItem.WebPages.Contains(
                        webPage => webPage.Roles.Contains(
                            "role"
                        )
                    )
                    or menuItem.PageIsNull
                )
            select menuItem;
    

    这应该只选择加入到具有适当角色的页面的菜单项。

    【讨论】:

    • 我也需要那些 PageID 为空的。
    • 我编辑了上面的查询以包括对空页面的检查。我对您的对象模型知之甚少,不知道要使用什么语法,但类似的东西应该可以工作。
    【解决方案2】:

    这应该会为你做的,伙计。您只需要说 WebPages.Any,如果任何菜单包含具有您指定角色的网页,这将返回 true。

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

    所以你需要添加的关键是这个。

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

    使用 Any() 函数非常有效,因为它会在找到匹配项后立即停止查找。

    如果你使用 Where() 然后 Count() 它将遍历所有网页以找到所有匹配项,然后遍历结果以计算它们,所以这样效率会低很多。

    下面是一个完整的源代码示例供您尝试。

        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;
                }
            }
    

    【讨论】:

      【解决方案3】:

      尝试改变

      public IQueryable<WebPage> WebPages
      

      public IEnumerable<WebPage> WebPages
      

      我认为 LINQ 查询返回 IEnumerable...

      【讨论】:

        【解决方案4】:

        DoctorJonez 谢谢!!!

        我把它放在这里是因为我有更多空间。我在菜单表中有 11 条记录,只有 1 条设置了 PageID 但是如果我使用

        var test = Menu.All().Where(x => x.WebPages.Any(pages => pages.Roles.Contains(Roles.GetRolesForUser()[0])
        

        我得到 11 条记录,因为 SQL 运行是这样的

        SELECT [t0].[CategoryID], [t0].[CreatedBy], [t0].[CreatedOn], [t0].[ID], [t0].[ImageID], [t0].[ImageIDHover], [t0].[Locale], [t0].[ModifiedBy], [t0].[ModifiedOn], [t0].[OrderID], [t0].[PageID], [t0].[ParentID], [t0].[Title], [t0].[URL], [t0].[Visible]
        FROM [dbo].[Menu] AS t0
        WHERE EXISTS(
          SELECT NULL 
          FROM [dbo].[WebPage] AS t1
          WHERE ([t1].[Roles] LIKE '%' + 'User' + '%')
          )
        

        如果我运行它,我会得到 1 条记录

        var test = Menu.All().Where(x => x.WebPages.Any(pages => pages.Roles.Contains(Roles.GetRolesForUser()[0]) && pages.ID == x.PageID));
        

        用于此的 SQL 是

        SELECT [t0].[CategoryID], [t0].[CreatedBy], [t0].[CreatedOn], [t0].[ID], [t0].[ImageID], [t0].[ImageIDHover], [t0].[Locale], [t0].[ModifiedBy], [t0].[ModifiedOn], [t0].[OrderID], [t0].[PageID], [t0].[ParentID], [t0].[Title], [t0].[URL], [t0].[Visible]
        FROM [dbo].[Menu] AS t0
        WHERE EXISTS(
          SELECT NULL 
          FROM [dbo].[WebPage] AS t1
          WHERE (([t1].[Roles] LIKE '%' + 'User' + '%') AND ([t1].[ID] = [t0].[PageID]))
          )
        

        这是 Subsonic 中的错误还是我理解不正确?

        Any()的问题是,在SQL中只要有一条记录退出,不管哪条记录都会返回数据。

        我认为实际上我想要一个如下所示的 UNION SQL,但我不知道如何将其重新设计为 C#/Subsonic

        select m.* from menu m where pageid is null
        
        union
        
        select m.* from menu m
        
        join webpage p
        on p.id = m.pageid
        
        where p.roles like '%User%'
        

        我想返回所有菜单记录,并且对于那些设置了相应网页在其中具有用户角色的 PageID 的记录。如果用户的角色不在网页中,那么我不想在结果中看到它。

        【讨论】:

        • 您可以编辑您的问题以包含此信息,因为它似乎是有关问题的更多详细信息而不是答案。
        猜你喜欢
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        • 2012-12-30
        • 1970-01-01
        • 1970-01-01
        • 2010-10-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多