提问人:MattoMK 提问时间:3/1/2023 最后编辑:MattoMK 更新时间:3/2/2023 访问量:81
分层数据并使用 LINQ 合并两个数据集
Hierarchical data and merging two data sets with LINQ
问:
我正在尝试合并来自两个不同服务调用的数据。数据在结构上与此类似:
API 层中的 DTO:
public static class GetData
{
public record Country
{
public Guid Id { get; set; }
public List<State> States { get; set; }
}
public record State
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<City> Cities { get; set; }
}
public record City
{
// this Id is stored in Service B's DB as ItemId
public Guid Id { get; set; }
public string Name { get; set; }
public Location Location { get; set; }
}
// From service B
public record Location
{
public Guid Id { get; set; }
public Guid ItemId { get; set; }
public string Name { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }
}
}
我需要将位置合并到正确的城市中,并一次性返回上面的整个结构。例如。
// this gets data including city (but no location) :
var country = await _serviceRequestA.GetCountryData();
// get list of Ids to make second call:
var ids = country.States.SelectMany(x => x.Cities).Select(x => x.Id).ToList();
// get list of location objects based on these ids:
var locations = await _serviceRequestB.GetLocations(ids);
尝试:通过城市将每个城市与每个位置进行匹配。ID 和位置。ItemId,找到后,将位置的 Id、Name、Latitude、Longitude 作为 Location 对象附加到城市。
// do something like this on each city:
// ...but all previous data,
cities.ForEach(c =>
{
c.Location = locations.Where(x => x.ItemId == c.Id)
.FirstOrDefault();
});
但是,我如何按原样获取每个父对象和子对象,包括城市?
同样,我的数据是:.country.states[n].cities[n]
我对 C# 或 LINQ 没有经验,除了简单的 where 和 selects。我是否必须进行多个循环并获取每个关卡的道具,然后应用合并逻辑?在 LINQ 中是否有更简洁的方法?
PS-这是当前从第一个服务调用返回的内容的json表示,另一个是合并后我想要的结果。我需要将 Location 对象附加到每个匹配的城市:
{
"country": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "US",
"states": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "California",
"cities": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "LA"
}
]
},
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Maine",
"cities": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Bangor"
}
]
}
]
}
}
因此,当我将数据返回到前端时,城市将如下所示:
{
"country": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "US",
"states": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "California",
"cities": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "LA",
"location": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Location X",
"latitude": "xxx",
"longitude": "xx-xx"
}
}
]
},
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Maine",
"cities": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Bangor",
"location": {
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"name": "Location Y",
"latitude": "yy",
"longitude": "yy-yy"
}
}
]
}
]
}
}
答:
1赞
Xinran Shen
3/1/2023
#1
从你的问题和评论来看,我认为这就是你想要的。
cities.ForEach(c =>
{
c.Location = locations.Where(x => x.ItemId == c.Id).FirstOrDefault();
});
或者,如果不想包含 的值,也可以使用以下代码:Itemid
cities.ForEach(c =>
{
c.Location = locations.Where(x => x.ItemId == c.Id).Select(x => new LocationA(){Id= x.Id,Name= x.Name,Latitude=x.Latitude,Longitude=x.Longitude}).FirstOrDefault();
});
更新:
如果要从国家/地区访问城市,只需使用两次即可。请注意,如果要输出不带 itemid 属性的 json,而不是 itemid 的值为 null,则需要更改代码,例如:Foreach(xxx)
public class City
{
// this Id is stored in Service B's DB as ItemId
public Guid Id { get; set; }
public string Name { get; set; }
public Object Location { get; set; }
}
然后:
country.States.ForEach(x =>
{
x.Cities.ForEach(y =>
{
y.Location = locationAs.Where(z => z.ItemId == y.Id).Select(d=> new {Id=d.Id,Name = d.Name, Latitude = d.Latitude, Longitude = d.Longitude }).FirstOrDefault();
});
});
输出:
您甚至可以看到属性没有映射数据,它只会显示 null。
评论
0赞
MattoMK
3/1/2023
是的,就是这个想法。但这就是我卡住的地方:我如何进入城市?以及如何在我下树时保持每个级别的现有属性?我有 where states and cities 是多个对象的列表。每个级别都是一个对象,还需要保留其他属性。一旦我到达城市级别并且树内没有损失,那么你的例子应该有效。这有意义吗?我可能没有很好地解释它。我应该发布示例json。country.states[n].cities[n]
0赞
MattoMK
3/2/2023
我试着在上面澄清。json 应该会有所帮助。
0赞
Xinran Shen
3/2/2023
请检查更新,希望它能解决您的问题。
0赞
MattoMK
3/2/2023
伟大。我想也许有一种 LINQ 模式以不同的方式处理这个问题。我会在几个小时内尝试。感谢您指出 null 的问题,但我们有处理所有这些和 json 的拦截器,如果它为 null,它甚至不会显示属性。
1赞
MattoMK
3/2/2023
当然可以!
评论
ItemId
Location
Id
City
var locations = await _serviceRequestB.GetLocations(ids);
Location
id, name