加入时不要忘记未受联接影响的数据

时间:2014-01-21 20:17:45

标签: c# .net linq linq-to-sql

我有三个我感兴趣的表,这里是相关信息:

+---------------+ +---------------+ +---------------+ +---------------+
| Class         | | Tests         | | StudentClasses| | Student       |
+---------------+ +---------------+ +---------------+ +---------------+
| ClassID       | | ClassID       | | ClassID       | | StudentID     |
|               | | WholeYearTest | | StudentID     | | StudentYear   |
|               | | TestYear      | |               | |               |
+---------------+ +---------------+ +---------------+ +---------------+

我有一个变量login,这是一个Student

我在LINQ中运行此查询:

        from tests in App.db.Tests
        join studentClasses in App.db.StudentClasses on tests.ClassID equals studentClasses.ClassID
        where (
         (tests.WholeYearTest == true && tests.TestYear == login.StudentYear)
         || 
         studentClasses.StudentID == login.StudentID
        )
        select tests;

不幸的是,我只得到符合条件studentClasses.StudentID == login.StudentID

的结果

我想要的是什么:

  • 由于StudentYear等于TestYearWholeYearTest为真,学生必须参加的所有考试
  • 学生必须参加的所有考试,因为与StudentClasses相关联的可能多个Tests.ClassID之一列在{{1}}下。

我认为 可能是由于对JOIN如何工作的公然误解 ,但我想不出任何其他方式来实现这一点。任何人都可以提出除循环所有测试之外的实现建议吗?如果没有,我想我会使用循环,但我确信必须有一些方法在LINQ中实现它。

2 个答案:

答案 0 :(得分:2)

我认为这会做你想做的事情:

from tests in App.db.Tests
join studentClasses in App.db.StudentClasses
on new { tests.ClassID, login.StudentID }
equals new { studentClasses.ClassID, studentClasses.StudentID }
into gj
from subStudentClass in gj.DefaultIfEmpty()
where (
 (tests.WholeYearTest == true && tests.TestYear == login.StudentYear)
 || 
 (subStudentClass != null && subStudentClass.StudentID == login.StudentID)
)
select tests

最大的区别是现在有outer join,因此您仍然可以找到加入失败的结果。

此外,现在加入ClassIDStudentID,以便您不会为其他学生提供匹配。

使用以下测试数据:

var App = new { db = new {
    Tests = new[] {
        new Test { ClassID = 1, WholeYearTest = true, TestYear = 1999 },
        new Test { ClassID = 2, WholeYearTest = true, TestYear = 1999 },
        new Test { ClassID = 3, WholeYearTest = false, TestYear = 1999 },
        new Test { ClassID = 4, WholeYearTest = false, TestYear = 1999 },
    },
    StudentClasses = new[] {
        new StudentClass { ClassID = 1, StudentID = 1 },
        new StudentClass { ClassID = 1, StudentID = 2 },
        new StudentClass { ClassID = 4, StudentID = 1 },
        new StudentClass { ClassID = 3, StudentID = 2 },
    }
} };
var login = new { StudentID = 1, StudentYear = 1999 };

Console.WriteLine(string.Join(Environment.NewLine, (
    //above query
  ).Select(x => string.Join(",", x.ClassID, x.WholeYearTest, x.TestYear))));

打印

1,True,1999 
2,True,1999 
4,False,1999 

答案 1 :(得分:1)

单个内部连接是不够的;您的查询实际上需要使用内部联接和联合执行。

尝试一下 - 我没有测试它,因为我认为你可以做到这一点:)

注意 - 您可能还需要在其中插入Distinct()。

var q1 = (from tests in App.db.Tests
          join studentClasses in App.db.StudentClasses 
             on tests.ClassID equals studentClasses.ClassID
          select tests).Concat(App.db.Tests.Where(t=>t.WholeYearTest && t.TestYear == login.StudentYear));