简体   繁体   English

LINQ 可查询

[英]LINQ IQueryable

I have a Menu class that has a IQueryable property called WebPages.我有一个菜单类,它有一个名为 WebPages 的 IQueryable 属性。 In the following statement I am returning Menu items based on a match but I need to include the Webpages property.在以下语句中,我将根据匹配项返回菜单项,但我需要包含 Webpages 属性。 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..我需要扩展它以检查 WebPage 类中的属性,就像这样..

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??注意:网页属性由 PageID 而非 CategoryID 填充,但不确定这是否有所不同??

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

If I understand the problem correctly, you want something like this:如果我正确理解这个问题,你想要这样的东西:

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

This should select only menu items joined to pages with the appropriate role.这应该只选择加入具有适当角色的页面的菜单项。

Try changing the尝试更改

public IQueryable<WebPage> WebPages

to

public IEnumerable<WebPage> WebPages

I think LINQ queries return IEnumerable...我认为 LINQ 查询返回 IEnumerable ...

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.您只需要说 WebPages.Any,如果任何菜单包含具有您指定角色的网页,这将返回 true。

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.使用Any()函数非常有效,因为它会在找到匹配项后立即停止查找。

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.如果您使用Where()然后Count()它将遍历所有网页以查找所有匹配项,然后遍历结果以对它们进行计数,因此效率会低得多。

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

DoctorJonez thanks!!!琼斯医生谢谢!!!

I'm putting this here as I have more space.我把它放在这里,因为我有更多的空间。 I have 11 records in the Menu table, only 1 with a PageID set however if I use我在菜单表中有 11 条记录,只有 1 条设置了 PageID,但是如果我使用

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

I get 11 records as the SQL run is this我得到 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' + '%')
  )

If I run this I get the 1 record如果我运行这个,我会得到 1 条记录

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

The SQL for this is这个 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]))
  )

Is this a bug in Subsonic or am I not understanding it correctly?这是 Subsonic 中的错误还是我没有正确理解它?

The problem with Any() is that in the SQL as long as one record exits, doesn't matter which record it will return data. Any() 的问题在于,在 SQL 中,只要存在一条记录,它会返回哪条记录并不重要。

I think effectively I am wanting an UNION SQL like below but I don't know how I re-engineer that into C#/Subsonic我认为有效地我想要一个像下面这样的 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%'

I want to return all menu records and for those with a PageID set that the corresponding WebPage has the user's role in it.我想返回所有菜单记录,并且对于那些设置了相应网页在其中具有用户角色的 PageID 的菜单记录。 If the user's role is not in the WebPage then I don't want to see it in my results.如果用户的角色不在网页中,那么我不想在结果中看到它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM