簡體   English   中英

使用聯接防止Entity Framework查詢中的SELECT N + 1問題

[英]Prevent SELECT N+1 issue in Entity Framework query using Joins

我正在嘗試從間接相關的實體中查詢某些內容到單一用途的視圖模型中。 這是我實體的復制品:

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”。

Gotcha:目前我無法更改實體 ,因此我不能僅在Member上包括List<Pet>屬性或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。 如果您希望包含上述內容的“即插即用”復制品,請參見此要點

通過不提供必要的導航屬性,使事情變得更加困難,正如注釋中提到的@Evk不會影響數據庫的結構,但是當您編寫諸如pet.Member.Team.Name類的pet.Member.Team.Name時,允許EF提供必要的聯接pet.Member.Team.Name (這里需要什么)。

模型的另一個問題是您既沒有從TeamPet的導航路徑,也沒有從PetTeam的導航路徑,因為“加入的”實體Member沒有導航屬性。

仍然可以通過一些不那么直觀的方式使用現有的導航屬性和不尋常的join運算符來獲得單個查詢所需的信息,如下所示:

var result = (
    from team in context.Teams
    from member in team.Members
    join pet in context.Pets on member.Id equals pet.Member.Id
    where pet.Name.Contains(pattern)
    select new PetViewModel
    {
        Name = pet.Name,
        TeamItIndirectlyBelongsTo = team.Name
    }).ToArray();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM