LINQ按属性过滤三个嵌套列表

3
我很新于使用LINQ,并遇到了一个似乎无法解决的问题。
所以,我基本上需要过滤嵌套在三个列表中的对象属性。 数据(作为JSON)如下所示:
  [
   {
      "userName":"John",
      "resourceTypeUserVms":[
         {
            "name":"Administration",
            "description":null,
            "resourceUserVms":[
               {
                  "policyUserVm":{
                     "policyName":"admin",
                     "priority":0,
                     "metaHash":"abc123",
                     "policySetName":"Admin",
                     "policySetDescription":""
                  },
                  "accessType":"Administration",
                  "accessDescription":null,
                  "metaData":"{\"Name\":\"Admin\"}"
               },
               {
                  "policyUserVm":{
                     "policyName":"test",
                     "priority":0,
                     "metaHash":"abc123",
                     "policySetName":"Test",
                     "policySetDescription":""
                  },
                  "accessType":"Administration",
                  "accessDescription":null,
                  "metaData":"{\"Name\":\"test123\"}"
               }
            ]
         },
         {
            "name":"Database",
            "description":null,
            "resourceUserVms":[
               {
                  "policyUserVm":{
                     "policyName":"read_x",
                     "priority":0,
                     "metaHash":"def456",
                     "policySetName":"Test",
                     "policySetDescription":""
                  },
                  "accessType":"read",
                  "accessDescription":null,
                  "metaData":"{\"Server\":\"srv\",\"Name\":\"test\"}"
               }
            ]
         },
         {
            "name":"Configuration",
            "description":null,
            "resourceUserVms":[
               {
                  "policyUserVm":{
                     "policyName":"readc",
                     "priority":0,
                     "metaHash":"ghi789",
                     "policySetName":"Configurations",
                     "policySetDescription":""
                  },
                  "accessType":"read",
                  "accessDescription":null,
                  "metaData":"{\"Name\":\"ServiceName\"}"
               }
            ]
         }
      ]
   }
]

我有一个用户,拥有x个ResourceTypesUserVms,每个ResourceTypes都有x个ResourceUserVms。

我需要过滤ResourceUserVms中的“metaData”属性。例如,在筛选栏中输入“Admin”,我希望得到如下返回结果:

[
   {
      "userName":"John",
      "resourceTypeUserVms":[
         {
            "name":"Administration",
            "description":null,
            "resourceUserVms":[
               {
                  "policyUserVm":{
                     "policyName":"admin",
                     "priority":0,
                     "metaHash":"abc123",
                     "policySetName":"Admin",
                     "policySetDescription":""
                  },
                  "accessType":"Administration",
                  "accessDescription":null,
                  "metaData":"{\"Name\":\"Admin\"}"
               }
            ]
         }
      ]
   }
]

我在网上找到了一些解决方案,建议我做以下操作:

filteredUsers = users
        .Where(x => x.ResourceTypeUserVms
        .Any(x => x.ResourceUserVms
        .Any(x => x.MetaData.ToLower().Contains(value))))
        .ToList();

然而,这并没有产生我想要的结果。

通过以下方式(下面是不规范的代码),我得到了期望的结果:

foreach(var user in users)
        {
            foreach(var resourceType in user.ResourceTypeUserVms)
            {
                foreach(var resource in resourceType.ResourceUserVms)
                {
                    if (resource.MetaData.ToLower().Contains(value))
                    {
                        filteredUsersTemp.Add(
                            new UserUserVm
                            {
                                UserName = user.UserName,
                                ResourceTypeUserVms = new List<ResourceTypeUserVm>(
                                    new ResourceTypeUserVm[] {
                                        new ResourceTypeUserVm
                                        {
                                            Description = resourceType.Description,
                                            Name = resourceType.Name,
                                            ResourceUserVms = new List<ResourceUserVm>(
                                                new ResourceUserVm[]{ resource }
                                                )
                                        }
                                    })
                            }
                            );
                    }
                }
            }
        }

我会尽力用LINQ找到一种优雅、干净的方法来解决这个问题,如有帮助不胜感激!

LINQ 的结果是什么?另外,您考虑过设置字典吗? - ejwill
LINQ返回了正确的用户,但是该用户所有的ResourceTypes和Resources都被返回了,而不仅仅是具有过滤值的那一个。不,我没有考虑过字典。您认为我能以何种方式使用它们? - Snoopy111
为了只返回相关的ResourceTypes和Resources,您需要改变这些列表。LINQ的.Where并不会改变项本身,它只影响从根集合中返回哪些项。您可以通过LINQ的.Select()方法返回与原始项不同的内容,但如果想要更改对象,则可能需要进行深度克隆 并更改resourceTypeUserVms属性。实际上,这需要分别处理这些任务的方法,并在LINQ中调用这些方法。 - asontu
@Snoopy111,这是因为你的Linq返回了具有搜索词的用户。如果您想指定要返回的数据,则需要在LINQ中使用Select。字典类似于使用LINQ,但键是您想要搜索的内容,并且适用于大型数据集。您还可以创建一个字典的字典。 - ejwill
2个回答

4

我猜你需要根据 MetaData 过滤 ResourceUserVms。

首先,获取所有具有 ResourceTypeUserVms 的用户,这些用户拥有具有 MetaData(== value)的 ResourceUserVms。你已经完成了这一步。

然后,可以摆脱无用的 MetaData ResourceUserVms。

   filteredUsers = users
            .Where(x => x.ResourceTypeUserVms
            .Any(x => x.ResourceUserVms
            .Any(x => x.MetaData.ToLower().Contains(value))))
            .ToList();

filteredUsers = filteredUsers.Select(x=>{

    x.ResourceTypeUserVms = x.ResourceTypeUserVms.Select(y=> {

       y.ResourceUserVms = y.ResourceUserVms.Where(s=>s.MetaData.ToLower().Contains(value)))).ToList();

       return y;

    }).ToList();

return x;

}).ToList();

你的 .Select() 跳过了 ResourceTypeUserVms,请修改 :) - asontu
非常感谢,那差不多就可以了。我必须添加 x.ResourceTypeUserVms = x.ResourceTypeUserVms.Where(z => z.ResourceUserVms.Count() > 0).ToList(); x; 这样我就不会得到空的ResourceTypes返回了。这就解决了问题! - Snoopy111

0
from user in users
from resourceType in user.ResourceTypeUserVms
from resource in resourceType.ResourceUserVms
where resource.MetaData.ToLower().Trim().Contains(value)

此外,建议使用Any()而不是Contains()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接