JamesEdCraig (2) [Avatar] Offline
#1
Hi all,

For the past couple of days I've been reading the excellent 'LINQ in Action'. During its coverage of 'LINQ to Objects' the book uses the following query expression to perform a left outer join:

***

from publisher in SampleData.Publishers
join book in SampleData.Books on publisher equals book.Publisher into publisherBooks
from book in publisherBooks.DefaultIfEmpty()
select new
{
Publisher = publisher.Name,
Book = book == default(Book) ? "(no books)" : book.Title
};

***

Basically, I'm hoping that some clever reader will be able to tell me how this query can be represented using pure query operator calls. If so, I'd be eternally grateful for their response as I'm truly at my wits end!

Many thanks indeed!

James
fabrice.marguerie (224) [Avatar] Offline
#2
Re: Can anyone convert this query expression into a query operator chain?
Hi James,

I'm not surprised that you haven't found how to write this query without the query expression syntax! It's not easy to do the conversion because it requires the use of tricks. Here the tricks are based on the use of anonymous types.

Here is the solution:

[pre]SampleData.Publishers
.GroupJoin(SampleData.Books,
publisher => publisher, book => book.Publisher,
(publisher, publisherBooks) => new { Publisher = publisher, PublisherBooks = publisherBooks })
.SelectMany(
group => group.PublisherBooks.DefaultIfEmpty<Book>(),
(group, book) => new {
Publisher = group.Publisher.Name,
Book = (book == null) ? "(no books)" : book.Title
});[/pre]
Not as easy to read as your original query, don't you think?

"How did he find that," you may be wondering... Well, even if I know the tricks, the easiest is to use .NET Reflector to decompile the IL.
If you specify ".NET 3.5" for the Optimization option, you'll see the query expression. But if you specify ".NET 2.0", you'll see something that looks close to the above query. You'll have to replace the anonymous methods with lambda expressions and change the name of the anonymous parameters to make the code somewhat more readable, though.

As usual, Reflector reveals a lot of secrets smilie

Fabrice
JamesEdCraig (2) [Avatar] Offline
#3
Re: Can anyone convert this query expression into a query operator chain?
Hi Fabrice,

Many thanks for taking the time to write this solution, and also for suggesting that neat Reflector trick! I'll most definitely be making good use of both in the future smilie

Finally, I have to congratulate you on your book. I began reading it a couple of days ago and have enjoyed immensely its lucid, comprehensive exploration of LINQ. The fact that the boss has granted me time to read it has made learning the subject more enjoyable still!

merci beaucoup!

James
fabrice.marguerie (224) [Avatar] Offline
#4
Re: Can anyone convert this query expression into a query operator chain?
You're welcome.
Thanks for sharing your impression. I'm glad that you're enjoying our book! smilie
fabrice.marguerie (224) [Avatar] Offline
#5
Re: Can anyone convert this query expression into a query operator chain?
Additional tips left as comments to the post on my blog:
- You can call ToString() on the Expression in the IQueryable created (if the query is of the IQueryable type)
- ReSharper has a convert to method chain option