![](/img/trans.png)
[英]Most efficient query to return multiple related entities in Entity Framework Core? (1:M and M:M)
[英]grouping and flatening 1:M:M:1 related data in Entity Framework Core/LINQ
在一個使用 Entity Framework 和 LINQ 的小型 ASP.NET Core Web API 中,我想實現一種方法來查詢一個人需要訪問的房間。 一個人想要的結果是這樣的
{
"id": 1,
"firstname": "First1",
"lastname": "Last1",
"rooms": [
{
"id": 1,
"name": "test room 1"
},
{
"id": 2,
"name": "test room 2"
},
{
"id": 3,
"name": "test room 3"
}
]
}
現在房間不是直接分配給一個人而是一個人有多個任務(每個任務只能有一個人),每個任務都需要訪問多個房間(所以任務和房間之間有一個M:N)。 房間表存儲房間 id 和名稱。
所以我有4張桌子:
表之間的連接是:
我目前的方法看起來像這樣
[HttpGet("RoomAccess/{personId:int}")]
public IActionResult RoomAccess(int personId)
{
_logger.LogDebug(string.Format("{0}.RoomAccess(person id: {1})", GetType().Name, personId));
var result = _dbContext.Person
.Include(p => p.Task).ThenInclude(t => t.TaskRoom).ThenInclude(tr => tr.Room)
.Where(p => p.Id == personId)
.Select(person => new
{
person.Id,
person.Firstname,
person.Lastname,
// how to do that line?
rooms = person.Task.Select(ta => ta.TaskRoom.Select(tr => new {id = tr.Room.Id, name = tr.Room.Name} ) )
}
)
.FirstOrDefault();
if (result == null)
{
return NotFound(string.Format("person id: {0}", personId));
}
return Ok(result);
}
到目前為止的結果:
{
"id": 1,
"firstname": "First1",
"lastname": "Last1",
"rooms": [
[
{
"id": 1,
"name": "test room 1"
}
],
[
{
"id": 2,
"name": "test room 2"
},
{
"id": 3,
"name": "test room 3"
}
],
[
{
"id": 3,
"name": "test room 3"
}
],
[]
]
}
對於尚未分配空間的任務(到目前為止),這里還有末尾的空括號[]
。 並且測試室 3 出現多次,因為兩個不同的任務需要訪問這個房間。
如何獲得僅包含房間 id 和名稱的相關房間的分組列表(如所需結果的示例)
歡迎任何幫助。
現在EF Core Github上有一個未解決的問題
那么工作代碼是:
[HttpGet("RoomAccess/{personId:int}")]
public IActionResult RoomAccess(int personId)
{
_logger.LogDebug(string.Format("{0}.RoomAccess(person id: {1})", GetType().Name, personId));
var result = _dbContext.Person
.Include(p => p.Task).ThenInclude(t => t.TaskRoom).ThenInclude(tr => tr.Room)
.Where(p => p.Id == personId)
.ToList()
.Select(person => new
{
person.Id,
person.Firstname,
person.Lastname,
rooms = person.Task.SelectMany(ta => ta.TaskRoom.Select(
tr => new { id = tr.Room.Id, name = tr.Room.Name })
)
.Distinct()
.OrderBy(adt => adt.name)
}
)
.FirstOrDefault();
if (result == null)
{
return NotFound(string.Format("person id: {0}", personId));
}
return Ok(result);
}
除了 Nkosi 的答案之外,在 Where() 之后使用 Include() 和 ThenInclude() 以及 .ToList() 也很重要。
使用SelectMany
擴展來展平列表。
//...
rooms = person.Task
.SelectMany(ta => ta.TaskRoom.Select(tr => new {id = tr.Room.Id, name = tr.Room.Name}))
.Distinct()
//...
不確定它將如何在 EF 中轉置以及任何性能影響。
請注意使用Distinct
刪除任何重復項。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.