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;
}
在哪里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 
    }
}
我想写这样的查询
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;
虽然这显然是无效的语法.上面链接的页面提供了一个非equijoin的例子,虽然我试图在这里应用它,似乎无法正确再现它(和/或我已经严重困惑自己).
我如何模仿join上面描述的类型?
首先,您的数据模型是错误的.学生没有单一年级.他们在课堂上有成绩,而你的模型没有考虑到这一点.你需要第三张表,列有学生,班级和年级.我强烈建议你解决这个问题.
解决上述问题很简单,但我不喜欢到目前为止提出的任何解决方案.它们大多数都是合理的,但效率更高,更强大.
您遇到的根本问题是:您没有快速简便的方法从学生ID转到学生对象.首先解决这个问题:
var idToStudent = allStudents.ToLookup(s => s.id);
大.现在解决方案很简单:
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;
请注意,我们正在测试是否有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;
在一组设计合理的表中,学生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;
检查Any的需要消失,因为C#不会产生空组.
那是你需要的联接; 正确设计你的表然后使用它!
| 归档时间: | 
 | 
| 查看次数: | 187 次 | 
| 最近记录: |