LINQ从多个级别选择ID

lmvvr0a8  于 2023-01-28  发布在  其他
关注(0)|答案(4)|浏览(142)

我想从所有嵌套实体中获取一个ID列表。
代码:

// Entities
class Floor
{
    public int Id { get; set; }
    public ICollection<Room> Rooms { get; set; } = new List<Room>();
}

class Room
{
    public int Id { get; set; }
    public ICollection<Chair> Chairs { get; set; } = new List<Chair>();
}
class Chair
{
    public int Id { get; set; }
}

// Setup
var floor = new Floor() { Id = 1000 };
var room = new Room() { Id = 100 };
var chair = new Chair() { Id = 10 };

room.Chairs.Add(chair);
floor.Rooms.Add(room);

var floors = new List<Floor>() { floor };

// Select all IDs
var ids = floors.???

预期结果:

{ 10, 100, 1000 }

我试过了。它只从最底层选择ID,而不是所有的:

// Select all IDs
var ids = floors
    .SelectMany(f => f.Rooms)
    .SelectMany(r => r.Chairs)
    .Select(ch => ch.Id)
    .ToList();
neekobn8

neekobn81#

SelectMany是与Append一起使用时所需的:

var ids = floors
    .SelectMany(f => f.Rooms
        .SelectMany(r => r.Chairs
            .Select(c => c.Id).Append(r.Id)).Append(f.Id));
qlvxas9a

qlvxas9a2#

当前代码将层次结构扁平化为Chair的集合,并只选择它们的id。
对于纯LINQ,您可以通过嵌套SelectMany并使用Append/Prepend来完成:

var ids = floors
    .SelectMany(f => f.Rooms
        .SelectMany(r => r.Chairs
            .Select(ch => ch.Id) // select chairs ids
            .Append(r.Id)) // append "current" room id to it's collection of chair ids
        .Append(f.Id)) // append "current" floor id to it's collection of rooms and chairs ids
    .ToList();
bxjv4tth

bxjv4tth3#

一个丑陋的黑客将附加“假货”的儿童房间/椅子与他们的父母的ID:

var ids = floors
    .SelectMany(f => f.Rooms.Append(new Room { Id = f.Id }))
    .SelectMany(r => r.Chairs.Append(new Chair { Id = r.Id }))
    .Select(ch => ch.Id)
    .ToList();
vlju58qv

vlju58qv4#

这可以通过递归helper函数来完成,如下所示:

IEnumerable<int> CollectIds<T>(T x) => x switch {
    Floor f => f.Rooms.SelectMany(CollectIds).Prepend(f.Id),
    Room r => r.Chairs.SelectMany(CollectIds).Prepend(r.Id),
    Chair c => Enumerable.Repeat(c.Id, 1),
    _ => throw new NotSupportedException()
};

用法:

var ids = floors
    .SelectMany(CollectIds)
    .ToList();

您可以考虑将此函数提取到一个公共接口中,以避免笨拙的类型切换和递归。

相关问题