Home > OS >  C# Linq - How do I flatten the output of a Join()?
C# Linq - How do I flatten the output of a Join()?

Time:06-08

I have a piece of C# Linq code that joins three tables; my code looks similar to the following (I have changed object names so as not to reveal sensitive information):

Customers
    .Join(Products, c => c.CustomerKey, p => p.CustomerKey, (c, p) => new { c, p })
    .Join(Transactions, p => p.p.AccountNumber, t => t.AccountNumber, (p, t) => new { p.c, p.p, t })

I'm using LinqPad for my testing, and when I look at the generated SQL, it looks correct; in fact, when I execute the SQL in SSMS, the output looks exactly as expected - a flat result set containing all the columns from the three tables.

The result set from the C# code, however, looks different: each record contains three columns, each storing the respective objects (Customer, Product, Transaction), as in this screenshot (sensitive data has been blacked out): enter image description here

Is there a simple way to display the results such that the properties for each object are combined and displayed horizontally as columns? In other words, so that it displays the same way as when the SQL is executed?

I realize, of course, that I could specify each column in an anonymous object via the new {....} statement at the end of the lambda expression. But it seems like there should be a simpler way to do this. Is there? Or do I in fact need to specify each property?

CodePudding user response:

I realize, of course, that I could specify each column in an anonymous object via the new {....} statement at the end of the lambda expression.

Yes, that's exactly what you need to do.

But it seems like there should be a simpler way to do this. Is there?

Currently, no.

The thing is: C# is a strongly-typed language, and Enumerable.Join needs a well-defined return type. The compiler can infer the return type from the lambda expression provided as the final argument, which at least saves you from having to define the new class explicitly.

Now, the C# language designers could create a feature that auto-generates a new type when Join is used with the LINQ query syntax. However, I consider this to be highly unlikely, since (a) the net benefit is low and (b) a lot of difficult design decisions would need to be made (how to handle properties that have the same name in both classes, etc.).

In general, C# developers seem to prefer explicitness (the code does exactly what I wrote) over "helpful magic". For example, in VB's implementation of LINQ query syntax, you can omit the select clause, and the compiler will automatically use the current iteration variable. In C#, a similar proposal was rejected.

  • Related