如何展平嵌套对象(LINQ)

时间:2016-09-13 16:04:34

标签: c# linq datagridview models

我在旧的Winforms网格上做了一些工作,我有两个模型,我试图压扁并分配给DataGridView。

以下是我的样本模型。

public class StockItem
{
     public string StockName { get; set; }
     public int Id { get; set; }
     public List<Warehouse> Warehouses { get; set; }
}

public class Warehouse
{
     public string WarehouseName { get; set; }
     public int Id { get; set; }
}

数据的工作方式必须首先创建仓库,然后分配给每个StockItemStockItem可能包含所有仓库,也可能只有一个仓库。

我需要展平数据,以便网格显示StockName,然后显示库存商品的所有相关仓库。

实施例

StockCode1      Warehouse1   Warehouse2   Warehouse3
StockCode2      Warehouse1   Warehouse2   
StockCode2      Warehouse1                Warehouse3   

我尝试通过Linq查询执行此操作,但每个StockItem \ Warehouse只能获取一条记录。

4 个答案:

答案 0 :(得分:1)

您可以通过创建一个DataTable来实现它,您可以轻松地将其用作gridview的源。首先添加所有列,然后为每个库存添加仓库:

var warehouseNames = 
    stocks
    .SelectMany(x => x.Warehouses.Select(y => y.WarehouseName)).Distinct();

var dt = new DataTable();
dt.Columns.Add("StockCode");

foreach (var name in warehouseNames)
{
    dt.Columns.Add(name);
}

foreach (var stock in stocks)
{
    var row = dt.NewRow();
    row["StockCode"] = stock.Id;
    foreach (var warehouse in stock.Warehouses)
    {
        row[warehouse.WarehouseName] = warehouse.Id;
    }
    dt.Rows.Add(row);
}

Warehouses

答案 1 :(得分:0)

推荐它,但您可以使用dynamic个对象创建具有所需形状的对象。 这样做不是常见的C#模式。这在Python或Javascript等语言中更为常见。

C#是一种强类型语言,冒险进入动态对象的世界,只有在绝对必要时才会考虑(想想解析json blob)。我强烈建议你重新评估你需要做的事情并从不同的角度来看待它。

答案 2 :(得分:0)

这样的事情:

var availableWarehouses = new [] { 
    new Warehouse { 
        WarehouseName = "Warehouse1",
        Id = 1
    },
    new Warehouse {
        WarehouseName = "Warehouse2",
        Id = 2
    },
    new Warehouse {
        WarehouseName = "Warehouse3",
        Id = 3
    }
};

var stocks = new [] {
    new StockItem {
        StockName = "StockCode1",
        Id = 1,
        Warehouses = new List<Warehouse> { availableWarehouses[0], availableWarehouses[1], availableWarehouses[2] }
    },
    new StockItem {
        StockName = "StockCode2",
        Id = 2,
        Warehouses = new List<Warehouse> { availableWarehouses[0], availableWarehouses[1] }
    },
    new StockItem {
        StockName = "StockCode3",
        Id = 3,
        Warehouses = new List<Warehouse> { availableWarehouses[0], availableWarehouses[2] }
    }
};

var flatten = stocks.Select(item => new {
        StockName = item.StockName,
        WarehousesNames = availableWarehouses.Select(warehouse => item.Warehouses.Contains(warehouse) ? warehouse.WarehouseName : "          ")
            .Aggregate((current, next) => current + "\t" + next)
    });

foreach(var item in flatten) {
    Console.WriteLine("{0}\t{1}", item.StockName, item.WarehousesNames);
}

答案 3 :(得分:-1)

那应该能满足你的需求:

var flattened = stockItems
    .Select(x => new { 
                 StockName = x.StockName, 
                 WarehouseNames = x.Warehouses
                                  .Select(y => y.WarehouseName)
                                  .ToList() })
    .ToList();

它将生成包含StockName的项目集合和WarehouseName字符串列表。添加了ToList来枚举查询。

对于这些样本数据:

List<StockItem> stockItems = new List<StockItem>
{
    new StockItem
    {
        StockName ="A",
        Id = 1,
        Warehouses = new List<Warehouse>
        {
            new Warehouse { Id = 1, WarehouseName = "x" },
            new Warehouse { Id = 2, WarehouseName = "y" }
        }
    },
    new StockItem
    {
        StockName = "B",
        Id = 2,
        Warehouses = new List<Warehouse>
        {
            new Warehouse { Id = 3, WarehouseName = "z" },
            new Warehouse { Id = 4, WarehouseName = "w" }
        }
    }
};

我得到了以下结果:

enter image description here