我試圖從間接相關的實體查詢到單一用途視圖模型的東西。這裏是我的實體的攝製:防止使用連接的實體框架查詢中的SELECT N + 1問題
public class Team {
[Key]
public int Id { get; set; }
public string Name { get; set; }
public List<Member> Members { get; set; }
}
public class Member {
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
public class Pet {
[Key]
public int Id { get; set; }
public string Name { get; set; }
public Member Member { get; set; }
}
每個類都在我的數據庫上下文DbSet<T>
。
這是我想從一個查詢,以構建視圖模型:
public class PetViewModel {
public string Name { get; set; }
public string TeamItIndirectlyBelongsTo { get; set; }
}
我與此查詢要這樣做:
public PetViewModel[] QueryPetViewModel_1(string pattern) {
using (var context = new MyDbContext(connectionString)) {
return context.Pets
.Where(p => p.Name.Contains(pattern))
.ToArray()
.Select(p => new PetViewModel {
Name = p.Name,
TeamItIndirectlyBelongsTo = "TODO",
})
.ToArray();
}
}
但顯然還是有「TODO」在那裏。
疑難雜症:我不能在這一刻改變實體,所以我不能只是包括List<Pet>
財產或Member
一個Team
屬性來助陣。我想在此時修復查詢內容。
這是我目前的解決方案:
public PetViewModel[] QueryPetViewModel_2(string pattern) {
using (var context = new MyDbContext(connectionString)) {
var petInfos = context.Pets
.Where(p => p.Name.Contains(pattern))
.Join(context.Members,
p => p.Member.Id,
m => m.Id,
(p, m) => new { Pet = p, Member = m }
)
.ToArray();
var result = new List<PetViewModel>();
foreach (var info in petInfos) {
var team = context.Teams
.SingleOrDefault(t => t.Members.Any(m => m.Id == info.Member.Id));
result.Add(new PetViewModel {
Name = info.Pet.Name,
TeamItIndirectlyBelongsTo = team?.Name,
});
}
return result.ToArray();
}
}
但是,這有一個 「SELECT N + 1」 的問題在那裏。
有沒有辦法創建一個一個 EF查詢得到所需的結果,而不改變實體?
PS。如果您更喜歡包含上述內容的「即插即用」再現器,請參閱this gist。
只是出於好奇 - 爲什麼你不能改變這些(很奇怪)實體?我的意思是,如果你修復它們,它不需要修改數據庫模型。 – Evk
@Evk好問題。一個原因是(現在)我真的想了解更多關於查詢的工作方式以及他們可以做什麼和不可以做什麼。原始理由不能從最小限度的repro中清楚表明,但歸結爲我想阻止其他人查詢此路線,除非他們真的知道他們在做什麼(並且不包括記錄中的財產是一種快速實現這一目標的方式)。 – Jeroen
我意識到這也意味着我可能需要接受一個答案「*不可能,改變你的實體無論如何你傻傻的*。」,如果事實證明是這樣的話。 – Jeroen