ENTERPRISE

LINQ to Objects : How to Join with Data in Another Sequence (part 3)

1/14/2014 3:07:36 AM
2.2 Simulating Outer Joins—Getting Unmatched Elements

Outer joins differ from inner joins in the way they handle missing and unmatched values. An outer join will return a result for outer elements that have no matching inner elements, whereas these elements would be skipped when using an inner join (as demonstrated in Listing 2).

To carry out an outer-join style query in LINQ to Objects, the DefaultIfEmpty standard query operator is used in the from clause of a join, and the null value generated by this operator handled in the select projection. Although this sounds difficult, Listing 3 demonstrates an outer join using the sample data shown in Table 2. This query is a little ambiguous at first glance, but in essence it injects a null element (the default value for an instance of Order type) for any Customer element that would have been removed by the inner join. This propagates a null value for order that any subsequent code working with that result property can process. In this example the ternary operator in the Console.WriteLine statement is catching and handling the null values by replacing those results with the string "(no orders)".

Listing 3. Structuring the query for an outer join where all outer-sequence records are returned, even though they have no orders—see Output 3
var customers = Customer.SampleData();
var orders = Order.SampleData();

var q = from c in customers
join o in orders on
c.CustomerID equals o.CustomerID into j
from order in j.DefaultIfEmpty()
select new
{
LastName = c.LastName,
Order = order
};

foreach (var element in q)
Console.WriteLine(
"Customer: {0} Order Number: {1}",
element.LastName.PadRight(9, ' '),
element.Order == null ?
"(no orders)" : element.Order.OrderNumber);

Output 3.
Customer: Gottshall   Order Number: Order 1
Customer: Gottshall Order Number: Order 2
Customer: Valdes Order Number: (no orders)
Customer: Gauwain Order Number: (no orders)
Customer: Deane Order Number: Order 3
Customer: Deane Order Number: Order 4
Customer: Zeeman Order Number: Order 5

The alternative to handling the null values in all places that will process the query result, is to handle the null instances in the actual select projection of the query itself, avoiding duplication of null handling code. T

var q1 = from c in customers
join o in orders on
c.CustomerID equals o.CustomerID into j
from order in j.DefaultIfEmpty()
select new
{
LastName = c.LastName,
OrderNumber = order == null ?
"(no order)" : order.OrderNumber
};

2.3 Joining by Composite Keys (More Than One Value)

Similar in approach to how multiple values can be used to specify the key value for grouping, composite keys are supported for joins by using anonymous types . In the case of joins, two anonymous types must be specified for the inner and outer keys as defined by the arguments on either side of the equals keyword.

The following example performs a one-to-one inner join between two in-memory collections. The key values used for joining are phone number and extension, combined using an anonymous type.

List<Contact> outer = Contact.SampleData();
List<CallLog> inner = CallLog.SampleData();

var q = from contact in outer
join call in inner on
new {
phone = contact.Phone,
contact.Extension
}
equals
new {
phone = call.Number,
call.Extension
}
select new { call, contact };

The anonymous types must match exactly—in property names and property order. In the previous example, it was necessary to specifically name the phone property because that property wasn’t the same name in both collections; Extension was the same, so the property name in the initializer could be omitted. (The compiler inferred the name to be Extension for this field.)

How Join Works

The query expression join syntax (like all the query expression keywords) map to the extension method appropriately named Join. This extension method takes two sequences (one as an extension method source outer, the other as an ordinary argument inner), two key selection functions (one for each source), and a result selection function. The Join extension method signature takes the following form:

public static IEnumerable<TResult>
Join<TOuter, TInner, TKey, TResult>(
this IEnumerable<TOuter> outer,
IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector,
Func<TInner, TKey> innerKeySelector,
Func<TOuter, TInner, TResult> resultSelector,
IEqualityComparer<TKey> comparer // optional
)

To understand how the Join operator works, the basic pseudo-code it carries out is as follows:

  1. Create a grouping on the inner sequence for all elements that share the same inner key selector function value (as determined by the innerKeySelector argument). Call this list of groups lookup.

  2. Iterate the outer sequence. Call each current element item.

    1. Create a grouping on the lookup sequence for all elements that share the same outer-key selector function value as this item (as determined by the outerKeySelector argument). If a comparer argument is supplied, use this comparer to calculate the equality.

    2. If there are any items in this grouping result

      1. Loop through all elements in this group

      2. Yield the result returned by the result selector on each element (using the resultSelector argument)

The returned sequence will be in the order of the outer sequence elements, one record for each matching inner element, followed by the next outer element’s records. Outer elements without matching inner elements will be skipped.

The key selection expression for the outer and inner sequence can be any expression that evaluates to a comparable type.

From the final query select projection, you have access to both sequences’ matching elements. The range variable can be used for both the inner and outer records throughout the query and referenced within the select projection expression to create a new type or an anonymous type.

Other  
  •  Moving into SAP Functional Development : Gaining Control of Change Control - How to Organize and Plan for Change in the Real World
  •  Moving into SAP Functional Development : Gaining Control of Change Control - Change Control and the SAP Solution Stack
  •  Moving into SAP Functional Development : Gaining Control of Change Control - Change Control Affects Everything
  •  Exchange Server 2010 : Outlook Integration (part 7) - Document Library Integration
  •  Exchange Server 2010 : Outlook Integration (part 6) - Alert Integration
  •  Exchange Server 2010 : Outlook Integration (part 5) - Task Integration
  •  Exchange Server 2010 : Outlook Integration (part 4) - Contact Integration
  •  Exchange Server 2010 : Outlook Integration (part 3) - Creating a Meeting Workspace
  •  Exchange Server 2010 : Outlook Integration (part 2) - Calendar Integration
  •  Exchange Server 2010 : Outlook Integration (part 1) - Integration Overview
  •  
    Top 10
    3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
    3 Tips for Maintaining Your Cell Phone Battery (part 1) - Charge Smart
    OPEL MERIVA : Making a grand entrance
    FORD MONDEO 2.0 ECOBOOST : Modern Mondeo
    BMW 650i COUPE : Sexy retooling of BMW's 6-series
    BMW 120d; M135i - Finely tuned
    PHP Tutorials : Storing Images in MySQL with PHP (part 2) - Creating the HTML, Inserting the Image into MySQL
    PHP Tutorials : Storing Images in MySQL with PHP (part 1) - Why store binary files in MySQL using PHP?
    Java Tutorials : Nested For Loop (part 2) - Program to create a Two-Dimensional Array
    Java Tutorials : Nested For Loop (part 1)
    REVIEW
    - First look: Apple Watch

    - 3 Tips for Maintaining Your Cell Phone Battery (part 1)

    - 3 Tips for Maintaining Your Cell Phone Battery (part 2)
    VIDEO TUTORIAL
    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

    - How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
    Popular Tags
    Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS