KDe*_*ker 3 c# linq iqueryable
我发现join操作员不允许使用,Contains因此只执行equijoins.但是,我需要执行"不等于".
我特别需要使用以下设置编写查询.鉴于两种类型的对象Class和Student
public class Class
{
public string Name { get; set; } = "";
public List<Guid> Students { get; set; } = new List<Guid>();
}
public class Student
{
public Guid StudentId { get; set; } = Guid.NewGuid();
public int Grade { get; set; } = 0;
}
Run Code Online (Sandbox Code Playgroud)
在哪里Class引用Student它们的StudentId.我想写一个条款,找出所有Class平均等级都Student高于某个值的条款.
class Program
{
static void Main(string[] args)
{
// Create all of the students
var class1Students = new List<Student>()
{
new Student() {Grade = 70 },
new Student() {Grade = 70 }
};
var class2Students = new List<Student>()
{
new Student() {Grade = 80 },
new Student() {Grade = 80 }
};
var class3Students = new List<Student>()
{
new Student() {Grade = 90 },
new Student() {Grade = 90 }
};
var allStudents = new List<Student>();
allStudents.AddRange(class1Students);
allStudents.AddRange(class2Students);
allStudents.AddRange(class3Students);
// Create all of the classes
var class1 = new Class()
{
Name = "Class1",
Students = class1Students.Select(s => s.StudentId).ToList()
};
var class2 = new Class()
{
Name = "Class2",
Students = class2Students.Select(s => s.StudentId).ToList()
};
var class3 = new Class()
{
Name = "Class3",
Students = class3Students.Select(s => s.StudentId).ToList()
};
var allClasses = new List<Class>() { class1, class2, class3 };
// Get all classes where the average grade is above 70
var query = from cls in allClasses
join std in allStudents on
}
}
Run Code Online (Sandbox Code Playgroud)
我想写这样的查询
var query = from cls in allClasses
join std in allStudents on cls.Students.Contains(std.StudentId) into clsStds
where clsStds.Select(aStd => aStd.Grade).Average() > 70
select cls;
Run Code Online (Sandbox Code Playgroud)
虽然这显然是无效的语法.上面链接的页面提供了一个非equijoin的例子,虽然我试图在这里应用它,似乎无法正确再现它(和/或我已经严重困惑自己).
我如何模仿join上面描述的类型?
首先,您的数据模型是错误的.学生没有单一年级.他们在课堂上有成绩,而你的模型没有考虑到这一点.你需要第三张表,列有学生,班级和年级.我强烈建议你解决这个问题.
解决上述问题很简单,但我不喜欢到目前为止提出的任何解决方案.它们大多数都是合理的,但效率更高,更强大.
您遇到的根本问题是:您没有快速简便的方法从学生ID转到学生对象.首先解决这个问题:
var idToStudent = allStudents.ToLookup(s => s.id);
Run Code Online (Sandbox Code Playgroud)
大.现在解决方案很简单:
var query =
from cls in allClasses
let grades = from id in cls.Students select idToStudent(id).Grade
where grades.Any()
where grades.Average() > 70
select cls;
Run Code Online (Sandbox Code Playgroud)
请注意,我们正在测试是否有Any成绩,因为可能有一个没有学生的班级.Average如果要求平均零项目将崩溃,所以检查是明智的.
当您修复数据模型以便正确地关联学生,班级和成绩时,它将是:
var query =
from cls in allClasses
let grades =
from grade in allGrades
where grade.Class == cls
select grade.grade
where grades.Any()
where grades.Average() > 70
select cls;
Run Code Online (Sandbox Code Playgroud)
在一组设计合理的表中,学生ID在计算平均值时不会进入; 您直接关联成绩和班级.
现在,您通过注意到您需要一种C#不支持的连接来启动此问题.不,您需要修复数据关系,然后C#支持您需要的连接类型!以上内容可以更有效地编写
var query =
from cls in allClasses
join g in allGrades on cls equals g.Class into grades
where grades.Average() > 70
select cls;
Run Code Online (Sandbox Code Playgroud)
检查Any的需要消失,因为C#不会产生空组.
那是你需要的联接; 正确设计你的表然后使用它!
| 归档时间: |
|
| 查看次数: |
187 次 |
| 最近记录: |