【问题标题】:LINQ filter by attribute nested in 3 listsLINQ 按嵌套在 3 个列表中的属性过滤
【发布时间】:2021-04-06 11:27:46
【问题描述】:

我对使用 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 的结果是什么?另外,您是否考虑过设置字典?
  • LINQ 返回正确的用户,但该用户的所有 ResourceTypes 和 Resources 都会返回,而不仅仅是具有过滤值的那个。不,我没有考虑过字典。你认为我可以以什么方式使用它们?
  • 为了只返回相关的 ResourceTypes 和 Resources,您需要改变这些列表。 LINQ 的.Where 不会这样做,它会影响根集合中的哪些项目被返回,它不会改变项目本身。您可以使用 LINQ 的 .Select() 返回与原始项目不同的内容,但为了改变对象,您可能需要 deep clone 它并更改 resourceTypeUserVms 属性。真正需要的是执行这些任务并在 LINQ 中调用这些方法的单独方法。
  • @Snoopy111 这是因为您拥有的 linq 正在返回具有您的搜索词的用户。如果要指定要返回的数据,则需要在 LINQ 中使用 Select 。字典类似于使用 LINQ,但关键是您要搜索的内容,并且适用于大型数据集。您也可以创建字典字典

标签: c# list linq nested filtering


【解决方案1】:

我猜,您还需要按 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,编辑了这个:)
  • 非常感谢,几乎成功了。必须添加 x.ResourceTypeUserVms = x.ResourceTypeUserVms.Where(z => z.ResourceUserVms.Count() > 0).ToList(); X;这样我就不会返回空的 ResourceTypes。成功了!
【解决方案2】:
from user in users
from resourceType in user.ResourceTypeUserVms
from resource in resourceType.ResourceUserVms
where resource.MetaData.ToLower().Trim().Contains(value)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-22
    • 1970-01-01
    相关资源
    最近更新 更多