The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

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