使用 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
上分组。我假设只有 MorningShift
和 EveningShift
列将 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 做了一个小修复。这是不正确的。
我需要一些帮助来解决这个问题。 我正在尝试将我的数据表转换为分层子列表,然后使用 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
上分组。我假设只有 MorningShift
和 EveningShift
列将 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 做了一个小修复。这是不正确的。