使用 linq 将数据表转换为子列表 - 检索行而不是按键分组

Converting Datatable to sublist using linq - retrieve rows without group by key

我需要一些帮助来解决这个问题。 我正在尝试将我的数据表转换为分层子列表,然后使用 LINQ 转换为 json。下面的代码运行完美。

var result = rows
    .GroupBy(x => new {b = x["Name"], a = x["Id"], c = x["MorningShift"], d = x["EveningShift"]})
    .OrderBy(a => a.Key.b)
    .Select(empl => new
    {
        Id = empl.Key.a,
        Name = empl.Key.b,
        MorningShift = empl.Key.c,
        EveningShift = empl.Key.d,
        Details = empl
            .Select(z => new
            {
                RouteId=z["RouteId"],
                ReportingHRName = z["ReportingHRName"],
                ShiftType = z["ShiftType"]
            })
            .OrderBy(a => a.ReportingHRName)

    });

员工可以上早班或晚班或两者兼而有之。我需要员工的详细信息作为子列表。我认为我的 LINQ 知识还不够好。我已经按 Name、Id、MorningShift、EveningShift 分组,使用键检索这些列。

但是这样做,如果员工的早班为空,那么将有单独的列表 - 具有空值和非空值。 (因为 GroupBy 完成了) 这是不希望的。

所以最后,我需要一些帮助来检索列 - morningshift 和 eveningshift 而不使用密钥。

注意:如果我尝试这样做

EveningShift = x["EveningShift"],
MorningShift = x["MorningShift"]

那么我不能select将每个员工的 ReportingHRName 和 ShiftType 作为子列表。

我得到了一个类似的 post (Convert Hierarchical DataTable to Json)。但这不能回答我的问题。

已编辑的数据表示例:

 Id   Name   MorningShift    EveningShift  RouteID ReportingHRName ShiftType
 1   abc       9               null         11      alex           full time
 2   def       8               null         12      robin          part time
 3   geh       null            5            13      shek           full time
 4   def       null            6            13      shek           part time

JSON 列表示例

    [{"Id":"1","Name":"abc","MorningShift":"9","EveningShift":"null","Details"[{"RouteId":"11","ReportingHRName":"alex","ShiftType":"full time"}]},{"Id":"2","Name":"def","MorningShift":"8","EveningShift":"6","Details":[{"RouteId":"12","ReportingHRName":"robin","ShiftType":"part time"}{"RouteId":"13","ReportingHRName":"shek","ShiftType":"full time"}]}{"Id":"3","Name":"geh","MorningShift":"null","EveningShift":"5","Details"[{"RouteId":"13","ReportingHRName":"shek","ShiftType":"full time"}]}]

因此,MorningShift 和 EveningShift 应该在没有按员工姓名 (Name) 分组的情况下检索。但是 RouteId、ReportingHRName 和 ShiftType 应该按员工分组检索。

如果像上面的代码那样按键检索 MorningShift 和 EveningShift,每个 MorningShift 和 EveningShift 将有单独的详细信息。

希望您能理解这个问题。感谢您的回复。

这是我尝试使用以下答案的代码。

 var groupedItems = dt.Rows.Cast<DataRow>()
.GroupBy(x => x["Name"])
.OrderBy(x => x["Name"])
.Select(x => new
{
    Name = x["Name"],
    MorningShift = x["MorningShift"]
    EveningShift = x["MorningShift"],
    Details = x.Select(y => new {RouteId=y["RouteId"],ReportingHRName=y["ReportingHRName"],ShiftType=y["ShiftType"]})
});.

但这会给我带来错误。无法在下面的代码中识别姓名、MorningShift 等。

    Name = x["Name"],
    MorningShift = x["MorningShift"]     

您不能在 JSON 中包含该行的 Id,因为它不允许进行任何分组(每一行都是唯一的,如果您确实需要,您可以带有 id 的数组)。要得到你想要的 JSON,你只需要在 Name 上分组。我假设只有 MorningShiftEveningShift 列将 AllowDbNull 设置为 true。如果你也有一些其他属性,你总是需要先用 IsColumnNameNull() 方法检查它。

所以这里有一个代码可以对您的数据进行分组:

var groupedItems = dt.Rows.Cast<YourDataTableType>()
    .GroupBy(x => x.Name)
    .OrderBy(x => x.Key)
    .Select(x => new
    {
        Name = x.Key,
        MorningShift = x.All(y => y.IsMorningShiftNull())
            ? null
            : x.Sum(y => y.IsMorningShiftNull() ? 0 : (int?) y.MorningShift),
        EveningShift = x.All(y => y.IsEveningShiftNull())
            ? null
            : x.Sum(y => y.IsEveningShiftNull() ? 0 : (int?) y.EveningShift),
        Details = x.Select(y => new {y.RouteId, y.ReportingHRName, y.ShiftType})
    });

然后你可以轻松地将其转换为JSON。我建议为此使用 JSON.NET

var json = JsonConvert.SerializeObject(groupedItems, Formatting.Indented);

而 JSON 将是:

[
  {
    "Name": "abc",
    "MorningShift": 9,
    "EveningShift": null,
    "Details": [
      {
        "RouteId": 11,
        "ReportingHRName": "alex",
        "ShiftType": "full time"
      }
    ]
  },
  {
    "Name": "def",
    "MorningShift": 8,
    "EveningShift": 6,
    "Details": [
      {
        "RouteId": 12,
        "ReportingHRName": "robin",
        "ShiftType": "part time"
      },
      {
        "RouteId": 13,
        "ReportingHRName": "shek",
        "ShiftType": "part time"
      }
    ]
  },
  {
    "Name": "geh",
    "MorningShift": null,
    "EveningShift": 5,
    "Details": [
      {
        "RouteId": 13,
        "ReportingHRName": "shek",
        "ShiftType": "full time"
      }
    ]
  }
]

编辑: 如果您的 DataTable 未键入并且您想按索引访问字段,则您的代码可能如下所示:

var groupedItems = dt.Rows.Cast<DataRow>()
    .GroupBy(x => x.Field<string>("Name"))
    .OrderBy(x => x.Key)
    .Select(x => new
    {
        Name = x.Key,
        MorningShift = x.All(y => y.IsNull("MorningShift"))
            ? null
            : x.Sum(y => y.Field<int?>("MorningShift")),
        EveningShift = x.All(y => y.IsNull("EveningShift"))
            ? null
            : x.Sum(y => y.Field<int?>("EveningShift")),
        Details = x.Select(y => new
        {
            RouteId = y.Field<int>("RouteId"),
            ReportingHRName = y.Field<string>("ReportingHRName"),
            ShiftType = y.Field<string>("ShiftType")
        })
    });

当然,如果您的某些字段有其他数据类型(例如 decimal 而不是 int),您应该更改它。

PS:我还在我的原始示例中对 LINQ 做了一个小修复。这是不正确的。