C#中如何合并两个IDbContext查询以获取关注俱乐部的比赛结果?
问题描述
我知道怎么从数据库取对应数据,但不确定C#里怎么实现这个需求:我有两个方法,第一个返回我关注的俱乐部列表,第二个返回指定俱乐部的比赛结果,现在想创建第三个方法,返回我关注的所有俱乐部的比赛结果。
获取关注俱乐部列表的代码
ImmutableArray<ClubInActiveSessionForMemberSqlModel> myClubs; using (var context = _contextFactory.CreateDbContext()) { myClubs = await context .ClubMembers .SetTracking(false) .Where(ClubMember => ClubMember.MemberId == memberId && ClubMember.ClubMemberRegistrationStatusTypeId == ClubMemberRegistrationStatusTypes.Registered.Id && (ClubMember.Club!.Session!.StartDateUtc > DateTime.UtcNow || ClubMember.Club!.Session.EndDateUtc > DateTime.UtcNow)) .Select(ClubMember => new ClubInActiveSessionForMemberSqlModel( ClubMember.ClubId, ClubMember.Club!.Name, ClubMember.Club.Session!.Id, ClubMember.Club.Session.Name, ClubMember.Club.Session.SessionTypeId, ClubMember.Club.ClubStanding!.ClubMatchWins, ClubMember.Club.ClubStanding.ClubMatchLosses )) .ToImmutableArrayAsync(); }
获取指定俱乐部比赛结果的代码
using (var context = _contextFactory.CreateDbContext()) { return await context .Clubs .SetTracking(false) .Where(t => t.Id == ClubId) .Select(t => new AllMatchResultsForClubByIdSqlModel( ClubId, t.Name, t.SessionId, t.Position1ClubMatches! .Where(tm => !completedOnly || (tm.ClubMatchResult != null && tm.ClubMatchResult.WinnerClubId.HasValue)) .AsQueryable() .Select(selectClubMatchResultSqlModelExpression) .AsEnumerable(), t.Position2ClubMatches! .Where(tm => !completedOnly || (tm.ClubMatchResult != null && tm.ClubMatchResult.WinnerClubId.HasValue)) .AsQueryable() .Select(selectClubMatchResultSqlModelExpression) .AsEnumerable())) .FirstOrDefaultAsync(); }
请问能不能把这两个查询合并成一个?我查过类似SQL语法的问题,但不确定C#里怎么实现。
解决方案
完全可以合并成一个查询,核心思路是从ClubMembers出发,先筛选出用户关注的有效俱乐部,再直接关联查询这些俱乐部的比赛结果,避免多次数据库往返。
合并后的完整代码
using (var context = _contextFactory.CreateDbContext()) { return await context .ClubMembers .SetTracking(false) .Where(cm => cm.MemberId == memberId && cm.ClubMemberRegistrationStatusTypeId == ClubMemberRegistrationStatusTypes.Registered.Id && (cm.Club!.Session!.StartDateUtc > DateTime.UtcNow || cm.Club.Session.EndDateUtc > DateTime.UtcNow)) // 直接关联Club实体,一次性获取比赛数据 .Select(cm => new AllMatchResultsForClubByIdSqlModel( cm.ClubId, cm.Club!.Name, cm.Club.SessionId, // 处理Position1的比赛结果 cm.Club.Position1ClubMatches! .Where(tm => !completedOnly || (tm.ClubMatchResult != null && tm.ClubMatchResult.WinnerClubId.HasValue)) .Select(selectClubMatchResultSqlModelExpression), // 处理Position2的比赛结果 cm.Club.Position2ClubMatches! .Where(tm => !completedOnly || (tm.ClubMatchResult != null && tm.ClubMatchResult.WinnerClubId.HasValue)) .Select(selectClubMatchResultSqlModelExpression) )) .ToImmutableArrayAsync(); }
关键说明
- 单次数据库请求:EF Core会自动将这个查询转换为带JOIN的SQL,只需要一次数据库往返,比先查俱乐部列表再逐个查比赛结果的性能更高。
- 简化子查询:移除了原代码中不必要的
AsQueryable()和AsEnumerable(),导航属性本身支持LINQ查询,EF Core能直接将子筛选逻辑转换为SQL。 - 返回类型调整:返回
ImmutableArray<AllMatchResultsForClubByIdSqlModel>,对应所有关注俱乐部的比赛结果集合。 - 空值处理:保留原代码的空值运算符
!,确保EF Core能正确解析导航属性(如果实体配置中这些导航属性是必选的,可考虑调整实体定义去掉空值运算符)。
额外优化提示
确保selectClubMatchResultSqlModelExpression是纯表达式树(不包含无法转换为SQL的本地方法),这样整个查询逻辑都会在数据库端执行,性能达到最优。
内容的提问来源于stack exchange,提问作者NewCSharp
相关产品推荐
相关产品推荐

