February 28, 2021
Hot Topics:

Implementing a Left Join with LINQ

  • By Paul Kimmel
  • Send Email »
  • More Articles »

Listing 3: All of the code to reproduce the data and run the sample.

Imports System.Data.Linq
Imports System.Data.Linq.Mapping
Imports System.IO

Module Module1

   Public connectionString As String = _
      "Data Source=BUTLER;Initial Catalog=Northwind;" + _
      "Integrated Security=True"

   Sub Main()
      ' Use LINQ to SQL to get the data - context represents
      ' the database
      Dim orderContext As DataContext =
         New DataContext(connectionString)
      Dim detailsContext As DataContext =
         New DataContext(connectionString)

      ' generic table does the ORM association
      Dim orders As Table(Of Order) =
         orderContext.GetTable(Of Order)()
      Dim details As Table(Of OrderDetail) =
         orderContext.GetTable(Of OrderDetail)()

      Dim allDetails = From detail In details _
                       Select detail

      For Each d In allDetails


      ' make sure we have some data

      ' define the left join - a group join with a twist
      Dim leftJoin = (From order In orders _
                      Group Join detail In details On _
                      order.OrderID Equals detail.OrderID _
                      Into children = Group _
                      From child In children.DefaultIfEmpty _
                      Select New With { _
                      .CustomerID = order.CustomerID, _
                      .OrderID = order.OrderID, _
                      .OrderDate = order.OrderDate, _
                      .ProductID = child.ProductID, _
                      .UnitPrice = child.UnitPrice, _
                      .Quantity = child.Quantity, _
                      .Discount = child.Discount}).Take(5)

   End Sub

   Function WriteLine(ByVal obj As Object) As Object
      Return Nothing
   End Function

   <System.Runtime.CompilerServices.Extension()> _
   Public Function Write(Of T)(ByVal obj As T, _
                               ByVal writer As TextWriter)

      If (TypeOf obj Is IEnumerable) Then
         Dim list As IEnumerable = obj
         For Each item In list
            Write(item, writer)
      End If

      Dim formatted = From info In obj.GetType().GetFields() _
                      Let value = info.GetValue(obj) _
                      Select New With {.Name = info.Name, _
                      .Value = IIf(value Is Nothing, "", value)}

      If (formatted.Count > 0) Then
         For Each one In formatted
         Dim alternate = From info In obj.GetType().GetProperties() _
            Let value = info.GetValue(obj, Nothing) _
            Select New With {.Name = info.Name, _
            .Value = IIf(value Is Nothing, "", value)}
         For Each one In alternate

      End If


      Return Nothing
   End Function

End Module

<Table(Name:="Orders")> _
Public Class Order
   <Column()> _
   Public OrderID As Integer
   <Column()> _
   Public CustomerID As String
   <Column()> _
   Public EmployeeID As Integer
   <Column()> _
   Public OrderDate As DateTime
   <Column()> _
   Public ShipCity As String
End Class

<Table(Name:="Order Details")> _
Public Class OrderDetail
   <Column()> _
   Public OrderID As Integer
   <Column()> _
   Public ProductID As Integer
   <Column()> _
   Public UnitPrice As Decimal
   <Column()> _
   Public Quantity As Int16
   <Column()> _
   Public Discount As Single


A left join is generally of the records in one set and only those records in the other set that are correlated to the records in the first set. I use the word records out of habit synonymously with objects. (Although in your example, rows of database data were used.) Although LINQ has no left join key phrase, the left join is supported through a group join and the DefaultIfEmpty method.

DefaultIfEmpty provides a default object when there are no child objects. Default child objects are necessary because LINQ supports defining a projection from parent and child objects, but in the left join, again, there may be no child and the object would in effect be null.

See you next month, same bate time, same bat channel.

About the Author

Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his upcoming book, LINQ Unleashed for C#, due in July 2008. Paul Kimmel is an Application Architect for EDS. You may contact him for technology questions at pkimmel@softconcepts.com.

If you are interested in joining or sponsoring a .NET Users Group, check out www.glugnet.org. Glugnet opened a users group branch in Flint, Michigan in August 2007. If you are interested in attending, check out the www.glugnet.org web site for updates.

Copyright © 2008 by Paul T. Kimmel. All Rights Reserved.

Page 2 of 2

This article was originally published on April 9, 2008

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date