2009-06-24 8 views
1

J'ai une classe Menu qui possède une propriété IQueryable appelée WebPages. Dans l'instruction suivante, je renvoie les éléments de menu en fonction d'une correspondance, mais je dois inclure la propriété Pages Web. Voici ce que j'ai en ce moment.Aide LINQ IQueryable

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

J'ai besoin de l'étendre pour vérifier une propriété dans la classe WebPage, quelque chose comme ça ..

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

Ce ne compilera pas, mais je l'espère, vous obtenez le jist de ce que je suis en train faire.

REMARQUE: la propriété Webpage est remplie par le PageID pas CategoryID, mais pas sûr si cela fait une différence?

Voici un bref aperçu de mes cours.

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

Répondre

0

Cela devrait le faire pour vous mate. Vous avez juste besoin de dire WebPages. Tout, cela retournera vrai si tous les menus contiennent une page Web avec votre rôle spécifié.

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

Alors panneton que vous avez besoin d'ajouter est la suivante.

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

Utilisation du Tout() fonction est très efficace car il ne regardera pas dès qu'il trouve une correspondance.

Si vous avez utilisé Où() puis Count() il itérer toutes les pages web pour trouver tous les matches, puis itérer les résultats pour les compter, donc ce serait beaucoup moins efficace.

Vous trouverez ci-dessous un exemple de source complète à essayer.

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

Essayez de changer la

public IQueryable<WebPage> WebPages 

à

public IEnumerable<WebPage> WebPages 

Je pense que les requêtes LINQ retour IEnumerable ...

0

DoctorJonez merci !!!

Je mets ça ici car j'ai plus d'espace.J'ai 11 enregistrements dans le tableau des menus, seulement 1 avec un jeu de PageID si j'utilise

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

Je reçois 11 dossiers comme la course SQL est ce

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' + '%') 
) 

Si je cours ce que je reçois la 1 enregistrement

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

Le SQL en est

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

Est-ce un bug dans Subsonic ou est-ce que je ne le comprends pas correctement?

Le problème avec Any() est que dans le SQL aussi longtemps qu'un enregistrement se termine, peu importe quel enregistrement il retournera des données.

Je pense effectivement que je suis désireux d'une SQL UNION comme ci-dessous, mais je ne sais pas comment je Restructurer cela en 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%' 

Je veux retourner tous les enregistrements de menu et pour ceux qui Un PageID défini que la page Web correspondante a le rôle de l'utilisateur dedans. Si le rôle de l'utilisateur ne figure pas dans la page Web, je ne souhaite pas le voir dans mes résultats.

+0

Vous auriez pu modifier votre question pour inclure cette information, car il semble y avoir plus de détails sur la question au lieu d'une réponse. – CoderDennis

1

Si je comprends bien le problème, vous voulez quelque chose comme ceci:

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

Cela devrait sélectionner les éléments de menu sont joints aux pages avec le rôle approprié.

+0

J'ai besoin de ceux où le PageID est nul aussi. – Jon

+0

J'ai modifié la requête ci-dessus pour inclure une vérification de la page null. Je ne connais pas assez votre modèle d'objet pour savoir quelle syntaxe utiliser, mais quelque chose comme ça devrait fonctionner. –