tags:

views:

175

answers:

1

I have 11 records in the Menu table, only 1 with a PageID set however if I use

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

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

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

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]))
)

The problem with Any() is that in the SQL as long as one record exits, doesn't matter which record it will return data.

I think effectively I am wanting an UNION SQL like below but I don't know how I re-engineer that into 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. If the user's role is not in the WebPage then I don't want to see it in my results.

Here are my cutodwn classes that Subsonic generates

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

It sure seems like you could just add an alternative test to the where clause to do this.

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

EDIT:

Try using the the Intersect method to see if there is an overlap between the roles in the DB and the roles for the user.

var test = Menu.All()
               .Where(x => x.PageID == null
                       || x.WebPages
                           .Any(pages => pages.Roles.Intersect(Roles.GetRolesForUser().Split(','))
                                            && pages.ID == x.PageID));
tvanfosson
Jon
Because you only want to check the roles for the matching page as I understand it. If you omit the check for PageID, then if any page in the collection is associated with the roles for the user, the menu will be included.
tvanfosson
Thanks. I need a slight tweak which I'm stuck on. If I take all the Roles the current authenitcated user is in and match it against the roles property in the DB, the DB value could be "administrator" but the Roles.GetRolesForUser could be "administrator,user,tech" so the Contains would fail. Could you help?
Jon
I've updated my answer to accomodate this (I think).
tvanfosson
pages.Roles is a string not a string[] so Intersect won't work
Jon
Is there only one role per page or is it delimited somehow? If there is only one role per page, you could turn the contains check around and see if the current roles contains the page role. If delimited, you may have to perform the query then filter server-side using some string manipulation/matching. I was assuming that you had a roles association not a column containing a role name(s).
tvanfosson
The roles column is just a varchar(200) delimeted with commas with role names. That could be changed if needed. There is usually at least 2 roles per page.
Jon