我有 3 個嵌套物體,TvShow、Season 和 Episodes:
public class TvShow
{
public Id { get; set; }
public List<Season> Seasons { get; set; }
}
public class Season
{
public Id { get; set; }
public int TvShowId { get; set; }
public TvShow TvShow { get; set; }
public List<Episode> Episodes { get; set; }
}
public class Episode
{
public Id { get; set; }
public int TvShowId { get; set; }
public TvShow TvShow { get; set; }
public int SeasonId { get; set; }
public Season Season { get; set; }
}
我正在嘗試撰寫一個查詢,我可以在其中提供以下輸入:
public List<int> TvShowIds { get; }
public List<int> TvShowSeasonIds { get; }
public List<int> TvShowEpisodeIds { get; }
這就是我卡住的地方,查詢應該包括所有不同型別的 id,包括它的子導航。
例如,對于 every TvShowId,它應該回傳TvShow包含所有Seasons和Episodes包含的物體。對于每一個SeasonId它應該包括它的所有Episodes和它的父TvShow。對于每一個EpisodeId,它應該包括它的父級Season,TvShow而不包括任何其他Episodes屬于相同的Season。
然后所有這些都應該作為一個合并的(聯合?)嵌套回傳,List<TvShow>()沒有任何重復。
我嘗試了不同的方法,但每次都卡住了。這應該不難,也許我在思考程序中遺漏了什么?
非常感謝幫助!
uj5u.com熱心網友回復:
鑒于您有(最多)3 個不同的過濾要求,這可能應該使用單獨的查詢來完成,因為您的代碼需要處理一些警告條件。例如,我可能會從一個季節或節目中選擇一個劇集 ID,我已經為其指定了一個節目或季節 ID,在這種情況下,我不想將該節目翻倍。
然后所有這些都應該作為合并的(聯合?)嵌套的 List() 回傳,沒有任何重復。
還有一種可能性是,對于給定的節目,我可能會通過季節過濾器選擇它,比如巴比倫 5 的第 2 季,然后提供一個劇集過濾器,選擇第 4 季的第 3 集。從你可能想要的聲音中在第 2 季的所有內容中檢索巴比倫 5(顯示),然后在第 3 集的第 4 季中檢索。
因為我們可能需要選擇由它們各自的劇集組成的多個季節,所以最好從劇集中攻擊這一點,然后從節目端重新組合視圖,它應該只列出所需的各個季節。
關于這種方法而不是投影的一個警告是結果物體將不再是資料的完整或可完整表示。通過僅使用所需劇集的子集選擇節目和季節,該節目和季節不再反映完整的劇集串列。如果將此物體傳遞給任何期望對 Show /w 季節和劇集的完整表示采取行動的方法,請務必小心。
List<Episodes> episodes = new List<Episode>();
IEnumerable<int> existingEpisodeIds = new List<int>();
if (filter.TvShowsIds.Any())
{
episodes.AddRange(Context.Episodes
.Include(x => x.Season)
.ThenInclude(x => x.TvShow)
.Where(x => filter.TvShowIds.Contains(x.Season.TvShow.Id))
.ToList());
existingEpisodeIds = episode.Select(x => x.id).ToList();
}
if (filter.SeasonIds.Any())
{
episodes.AddRange(Context.Episodes
.Include(x => x.Season)
.ThenInclude(x => x.TvShow)
.Where(x => !existingEpisodeIds.Contains(x.Id)
&& filter.SeasonIds.Contains(x.Season.Id)
.ToList());
existingEpisodeIds = episodes.Select(x => x.id).ToList();
}
if (filter.Episodes.Any())
{
episodes.AddRange(Context.Episodes
.Include(x => x.Season)
.ThenInclude(x => x.TvShow)
.Where(x => !existingEpisodeIds.Contains(x.Id)
&& filter.EpisodeIds.Contains(x.Id)))
.ToList();
}
var shows = episodes.Select(x => x.Season.Show).Distinct().ToList();
通過從劇集中攻擊這一點并在該方向上急切地加載相應的季節和節目,每個選定的劇集都會出現相關的季節,就像電視節目一樣。這意味著結果節目中出現的唯一季節將是導致選擇至少一集的季節。我們跟蹤選定的劇集 ID 并通過后續搜索對其進行重繪 ,以避免將回傳的劇集加倍。(即第 2 季中的第 3 集,如果已經選擇了第 2 季的所有劇集,或該節目的所有劇集)
這種方法的警告是它假設所有節目都有季節并且所有季節都有情節,我認為這是一個安全的假設。例如,如果您的 TvShow Id #99 沒有季節或劇集,并且 TvShowId 過濾器為 99,則不會回傳,因為我們正在查詢劇集。
uj5u.com熱心網友回復:
假設我已經正確理解了您的問題,我懷疑 EF 核心是否能夠翻譯,除非它是在記憶體中完成的,但您可以試試這個:
await Db.TvShows
.Where(x => TvShowIds.Contains(x.Id))
.Select(x => { x.Seasons = x.Seasons.Where(y => TvShowSeasonsIds.Contains(y.Id))
.Select(y => { y.Episodes = y.Episodes.Where(z => TvShowEpisodeIds.Contains(z.Id)).ToList(); return y; }).ToList(); return x; })
.ToListAsync();
編輯,我剛剛在 .Net Core 3.1 中嘗試了以下內容,它似乎有效。如果您需要向上的相關物體,您可以添加到選擇中。您可能也應該使用 DTO 而不是實際的 EF 核心物體創建資料傳輸物件 (DTO)
await Db.TvShows
.Where(x => TvShowIds.Contains(x.Id))
.Select(x => new TvShow
{
Id = x.Id,
Seasons = x.Seasons.Where(y => TvShowSeasonsIds.Contains(y.Id))
.Select(y => new Season
{
Id = y.Id,
TvShowId = y.TvShowId,
Episodes = y.Episodes.Where(z => TvShowEpisodeIds.Contains(z.Id)).ToList(),
}).ToList()
}).ToListAsync();
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/313325.html
