RoL*_*LLs 5 c# linq lambda linq-method-syntax
我有 3 个课程,并试图用它LINQ methods来执行 anINNER JOIN和 a LEFT JOIN。我可以单独执行每个操作,但不能一起执行,因为我什至无法弄清楚语法。
最终,我要编写的 SQL 是:
SELECT *
FROM [Group] AS [g]
INNER JOIN [Section] AS [s] ON [s].[GroupId] = [g].[Id]
LEFT OUTER JOIN [Course] AS [c] ON [c].[SectionId] = [s].[Id]
Run Code Online (Sandbox Code Playgroud)
课程
public class Group {
public int Id { get; set; }
public int Name { get; set; }
public bool IsActive { get; set; }
public ICollection<Section> Sections { get; set; }
}
public class Section {
public int Id { get; set; }
public int Name { get; set; }
public int GroupId { get; set; }
public Group Group { get; set; }
public bool IsActive { get; set; }
public ICollection<Course> Courses { get; set; }
}
public class Course {
public int Id { get; set; }
public int UserId { get; set; }
public int Name { get; set; }
public int SectionId { get; set; }
public bool IsActive { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
样品
我希望结果是 类型Group。我成功地执行了和LEFT JOIN之间的操作,但随后我有一个a> Group`类型的对象。SectionCourseIQueryable<, which is not what I want, since
public class Group {
public int Id { get; set; }
public int Name { get; set; }
public bool IsActive { get; set; }
public ICollection<Section> Sections { get; set; }
}
public class Section {
public int Id { get; set; }
public int Name { get; set; }
public int GroupId { get; set; }
public Group Group { get; set; }
public bool IsActive { get; set; }
public ICollection<Course> Courses { get; set; }
}
public class Course {
public int Id { get; set; }
public int UserId { get; set; }
public int Name { get; set; }
public int SectionId { get; set; }
public bool IsActive { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我也尝试过此操作,但返回,NULL因为这INNER JOIN对所有表执行了 an 操作,并且用户尚未输入任何Courses.
var result = db.Section
.GroupJoin(db.Course,
s => s.Id,
c => c.SectionId,
(s, c) => new { s, c = c.DefaultIfEmpty() })
.SelectMany(s => s.c.Select(c => new { s = s.s, c }));
Run Code Online (Sandbox Code Playgroud)
问题
如何以最少的数据库调用次数执行 anINNER和 a并获得类型的结果?LEFT JOINGroup
期望的结果
我想要 1 个类型的对象Group,但前提是 aGroup具有Section. 我还想返回Courses用户具有的特定Section或 return NULL。
Group我认为如果不返回一个新的(匿名)对象而不是(如本答案所示),您所要求的就是不可能的。由于关系和实体缓存的工作方式,EF 不允许您Course在 a 中获取已过滤的集合,这意味着您无法使用导航属性来执行此任务。Section
首先,您希望控制加载哪些相关实体,因此我建议通过在实体中标记Sections和Courses集合属性来启用延迟加载virtual(除非您已为应用程序中的所有实体启用延迟加载),因为我们不希望 EF 加载相关内容Sections,Courses因为它无论如何都会加载每个用户的所有课程。
public class Group {
public int Id { get; set; }
public int Name { get; set; }
public bool IsActive { get; set; }
public virtual ICollection<Section> Sections { get; set; }
}
public class Section {
public int Id { get; set; }
public int Name { get; set; }
public int GroupId { get; set; }
public Group Group { get; set; }
public bool IsActive { get; set; }
public virtual ICollection<Course> Courses { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在方法语法中,查询可能如下所示:
var results = db.Group
.Where(g => g.IsActive)
.GroupJoin(
db.Section.Where(s => s.IsActive),
g => g.Id,
s => s.GroupId,
(g, s) => new
{
Group = g,
UserSections = s
.GroupJoin(
db.Course.Where(c => c.IsActive && c.UserId == _userId).DefaultIfEmpty(),
ss => ss.Id,
cc => cc.SectionId,
(ss, cc) => new
{
Section = ss,
UserCourses = cc
}
)
})
.ToList();
Run Code Online (Sandbox Code Playgroud)
您将把结果消费为:
foreach (var result in results)
{
var group = result.Group;
foreach (var userSection in result.UserSections)
{
var section = userSection.Section;
var userCourses = userSection.UserCourses;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,如果您不需要在数据库级别对分组结果进行额外过滤,您还可以使用此 LINQ 查询采用 INNER JOIN 和 LEFT OUTER JOIN 方法,并在内存中进行分组:
var results = db.Group
.Where(g => g.IsActive)
.Join(
db.Section.Where(s => s.IsActive),
g => g.Id,
s => s.GroupId,
(g, s) => new
{
Group = g,
UserSection = new
{
Section = s,
UserCourses = db.Course.Where(c => c.IsActive && c.UserId == _userId && c.SectionId == s.Id).DefaultIfEmpty()
}
})
.ToList() // Data gets fetched from database at this point
.GroupBy(x => x.Group) // In-memory grouping
.Select(x => new
{
Group = x.Key,
UserSections = x.Select(us => new
{
Section = us.UserSection,
UserCourses = us.UserSection.UserCourses
})
});
Run Code Online (Sandbox Code Playgroud)
请记住,每当您尝试访问group.Sections或时section.Courses,您都会触发延迟加载,它将获取所有子部分或课程,而不管_userId.
| 归档时间: |
|
| 查看次数: |
3120 次 |
| 最近记录: |