Search code examples
c#asp.net-mvclinqef-database-first

LINQ filter list based on property value and filter the properties as well


My NavigationItem has navigation property NavigationItemsPermissions where I have RoleId. As input parameter in function I have List<int> roleIds where I will have something like {1, 3}.

How do I finish my LINQ to give me back NavigationItem(s) that has NavigationItemsPermissions with some RoleId on the input list. Note that, additionally, I want only those NavigationItemsPermissions with RoleId from the input list.

Here is where I'm stuck at

public List<NavigationItem> GetNavigationItems(MenuType menuType, List<int> roleIds)
{
    var navigationItems = DbContext.NavigationItems.Where(x => x.MenuTypeId == (int) menuType && !x.IsDeleted && x.NavigationItemsPermissions.Any(r=>r.RoleId **in roleIds**)));       

    return navigationItems;
}

To give a simpler analogy (not real data), if there is a list of developers

developers: [
    { name: "Hickory", skills: ["c#", "js", "linq"] }
    { name: "Dickory", skills: ["html", "css", "js"] }
    { name: "Dock", skills: ["html", "c#", "oracle"] }
]

And a given list of skills list = [ "c#", "linq" ], I want the following as result

[{ name: "Hickory", skills: ["c#", "linq"] }
{ name: "Dock", skills: ["c#"] }]

Sample real data:

enter image description here

enter image description here

Thank you for any help.


Solution

  • This should give you the desired result

    public List<NavigationItem> GetNavigationItems(MenuType menuType, List<int> roleIds)
    {
        var navigationItems = DbContext.NavigationItems
                                            .Where(x => x.MenuTypeId == (int) menuType && 
                                                    !x.IsDeleted && 
                                                    x.NavigationItemsPermissions.Any(r => roleIds.Contains(r.RoleId)));
        return navigationItems;
    }
    

    Edit

    If you " only need NavigationItemsPermissions where NavigationItemsPermissions.RoleId is in roleIds", you can use this query

    var navigationPermissions = DbContext.NavigationItems
                                        .Where(x => x.MenuTypeId == (int) menuType && 
                                                !x.IsDeleted)
                                        .SelectMany(ni => ni.NavigationItemsPermissions)
                                        .Where(np => roleIds.Contains(np.RoleId))
                                        .ToList();
    

    Use Distinct() before ToList() if there are repeated items and you want only distinct items.

    Edit 2

    var navigationItems = DbContext.NavigationItems
                                        .Where(x => x.MenuTypeId == (int) menuType && 
                                                !x.IsDeleted && 
                                                x.NavigationItemsPermissions.Any(r => roleIds.Contains(r.RoleId)));     
    navigationItems.ForEach(x => x.NavigationItemsPermissions = x.NavigationItemsPermissions.Where(r => roleIds.Contains(r.RoleId)).ToList());