Results 1 to 4 of 4

Thread: How do I get a left outer join in LINQ.

  1. #1

    Thread Starter
    PowerPoster abhijit's Avatar
    Join Date
    Jun 1999
    Location
    Chit Chat Forum.
    Posts
    3,228

    How do I get a left outer join in LINQ.

    Here is my code.

    C# Code:
    1. namespace LINQMatching
    2. {
    3.     class Student
    4.     {
    5.         public int StudentId { get; set; }
    6.         public string Name { get; set; }
    7.         public DateTime DateOfBirth { get; set; }
    8.     }
    9.    
    10.     class Exam
    11.     {
    12.         public int TestId { get; set; }
    13.         public string Name { get; set; }
    14.     }
    15.  
    16.     class ExamScore
    17.     {
    18.         public int StudentId { get; set; }
    19.         public int TestId { get; set; }
    20.         public DateTime TestDate { get; set; }
    21.         public decimal ? Score { get; set; }
    22.     }
    23.  
    24.     class StudentScore
    25.     {
    26.         public int StudentId { get; set; }
    27.         public string StudentName { get; set; }
    28.         public int TestId { get; set; }
    29.         public string TestName { get; set; }
    30.         public decimal? TestScore { get; set; }
    31.         public DateTime TestDate { get; set; }
    32.     }
    33.  
    34.     class LinqMatching
    35.     {
    36.        static List<Student> students = new List<Student>();
    37.        static List<Exam> exams = new List<Exam>();
    38.        static List<ExamScore> scores = new List<ExamScore>();
    39.  
    40.         static void PopulateLists()
    41.         {
    42.             students = new List<Student>
    43.                 {
    44.                     new Student {StudentId = 101, Name = "Steyn Jacob", DateOfBirth = new DateTime(1987, 1, 1)},
    45.                     new Student {StudentId = 102, Name = "Elisha Martin", DateOfBirth = new DateTime(1989, 1, 1)},
    46.                     new Student {StudentId = 103, Name = "Chad Gomes", DateOfBirth = new DateTime(1989, 11, 21)},
    47.                     new Student {StudentId = 104, Name = "Jim Martin", DateOfBirth = new DateTime(1989, 12, 1)}
    48.                 };
    49.             exams = new List<Exam>
    50.                 {
    51.                     new Exam {TestId = 10, Name = "English"},
    52.                     new Exam {TestId = 11, Name = "Math"},
    53.                     new Exam {TestId = 13, Name = "Science"},
    54.                     new Exam {TestId = 14, Name = "Geography"},
    55.                     new Exam {TestId = 16, Name = "French"},
    56.                     new Exam {TestId = 15, Name = "History"}
    57.                 };
    58.             scores = new List<ExamScore>
    59.                 {
    60.                     new ExamScore {TestId = 10, Score = 9.11M, StudentId = 101, TestDate = new DateTime(2013, 1, 1)},
    61.                     new ExamScore {TestId = 11, Score = 8.11M, StudentId = 101, TestDate = new DateTime(2013, 2, 1)},
    62.                     new ExamScore {TestId = 13, Score = 8.11M, StudentId = 101, TestDate = new DateTime(2013, 3, 1)},
    63.                     new ExamScore {TestId = 10, Score = 9.11M, StudentId = 102, TestDate = new DateTime(2013, 1, 1)},
    64.                     new ExamScore {TestId = 10, Score = 9.11M, StudentId = 104, TestDate = new DateTime(2013, 1, 1)}
    65.                 };
    66.         }
    67.  
    68.         static void Main(string[] args)
    69.         {
    70.             var queryOut = from s in students
    71.                            join e in scores on s.StudentId equals e.StudentId
    72.                            join t in exams on e.TestId equals t.TestId
    73.                            select new StudentScore
    74.                                {
    75.                                    StudentName = s.Name,
    76.                                    TestId = e.TestId,
    77.                                    TestName = t.Name,
    78.                                    TestDate = e.TestDate,
    79.                                    StudentId = s.StudentId,
    80.                                    TestScore = e.Score
    81.                                };
    82.             foreach (var s in queryOut)
    83.             {
    84.                 Console.WriteLine("{0} {1} {2} {3} {4}",s.StudentId, s.StudentName, s.TestName, s.TestDate, s.TestScore);
    85.             }
    86.         }
    87.     }
    88. }
    89.  
    90. i wish to know the syntax for getting this join to work. The output I expect from the query is
    91. StudentName - TestName - TestDate - TestScore
    92.  
    93. The list must contain all the students and all the tests. If a student hasn't taken a test, the testscore and testdate would be empty.
    94. How can I form this query?
    Everything that has a computer in will fail. Everything in your life, from a watch to a car to, you know, a radio, to an iPhone, it will fail if it has a computer in it. They should kill the people who made those things.- 'Woz'
    save a blobFileStreamDataTable To Text Filemy blog

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: How do I get a left outer join in LINQ.

    You use the DefaultIfEmpty method on the right-hand list to perform a left outer join:

    http://www.hookedonlinq.com/OuterJoinSample.ashx
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3

    Thread Starter
    PowerPoster abhijit's Avatar
    Join Date
    Jun 1999
    Location
    Chit Chat Forum.
    Posts
    3,228

    Re: How do I get a left outer join in LINQ.

    Quote Originally Posted by jmcilhinney View Post
    You use the DefaultIfEmpty method on the right-hand list to perform a left outer join:

    http://www.hookedonlinq.com/OuterJoinSample.ashx
    That would work very well with two tables, but with three lists, I run into a bit of a problem.

    Here's my code to join the three lists.

    C# Code:
    1. var leftJoin = from s in students
    2.                            join e in scores on s.StudentId equals e.StudentId into joinedScores
    3.                            from jS in joinedScores.DefaultIfEmpty()
    4.                                select new
    5.                                    {
    6.                                      score = jS ==null ? 0 :  jS.Score,
    7.                                      testDate = jS == null ? "Did Not Take Test" : jS.TestDate.ToString("yyyy-dd-MM"),
    8.                                      testId = jS == null ? 0 :jS.TestId,
    9.                                      studentName = s.Name
    10.                                    };
    11.  
    12.             var secondLeft = from t in exams join lj in leftJoin on t.TestId equals lj.testId into joinedTests
    13.             from jt in joinedTests.DefaultIfEmpty()
    14.                         select new
    15.                                 {
    16.                                     testName = t.Name,
    17.                                     testId = t.TestId,
    18.                                     score = jt == null ? 0 : jt.score,
    19.                                     testDate = jt == null ? "Did not take test" : jt.testDate,
    20.                                     studentName = jt == null ? "Not available" : jt.studentName
    21.                                 };
    22.  
    23.            
    24.             foreach (var lJ in secondLeft)
    25.             {
    26.                 Console.WriteLine("{3} \t{0}\t{1}\t{2}", lJ.score, lJ.studentName, lJ.testDate, lJ.testName);
    27.             }

    here is the output it produces
    PHP Code:
    English         9.11    Steyn Jacob     2013-01-01
    English         9.11    Elisha Martin   2013
    -01-01
    English         9.11    Jim Martin      2013
    -01-01
    Math    8.11    Steyn Jacob     2013
    -01-02
    Science         8.11    Elisha Martin   2013
    -01-03
    Geography       0       Not available   Did not take test
    French  0       Not available   Did not take test
    History         0       Not available   Did not take test 
    I would instead prefer to have a listing that has all the students as well as all the tests.
    Everything that has a computer in will fail. Everything in your life, from a watch to a car to, you know, a radio, to an iPhone, it will fail if it has a computer in it. They should kill the people who made those things.- 'Woz'
    save a blobFileStreamDataTable To Text Filemy blog

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: How do I get a left outer join in LINQ.

    I don't have time to try it myself right now but, if my understanding of what you want is correct, here's what I would try. Try performing two queries: one that gets the data including all students and another that gets the data including all exams. They will both returns lists of instances of the same type though. You can then perform a Union and a Distinct and that should give you one copy of everything. You may have to override Equals or GetHashCode or both in the result type in order to get Distinct to work as required.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width