Stupid LINQ tricks (Originally published 10/5/07)

This won’t be news to any of the Microsoft gurus or MVP’s, but it struck me as pretty friggin’ cool, so I thought I’d share it.  If you’ve read any of Scott Guthrie’s blogs, then you’ve seen some cool stuff like the new type initializer syntax.  It’s what lets you write stuff like this:

Person person = new Person { FirstName = "Joe", LastName = "Bob", Age = 32 };

Instead of this:

Person person = new Person();
person.FirstName = "Joe";
person.LastName = "Bob";
person.Age = 32;

It’s kind of like a pseudo-constructor.  But did you know that you can use it with regular constructors as well?

public class Person
{
    public string FirstName { get; set; }
    public string LastName  { get; set; }       
    public int Age { get; set; }

    public Person(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }
}

private static void InitializerTest()
{
    Person person = new Person("Joe", "Bob") { Age = 32 };
}

Yeah, no-one mentions that, but it works just fine.  After all, it’s just syntactic sugar, it ends up meaning the exact same thing on the back-end.  I just decided to try it to see what it’d do, and it worked just fine.  RAWK!

So what good is that?  It’s really good, because it lets us initialize and fill in NON-anonymous classes when performing LINQ queries.  Everyone’s so busy writing articles showing how to LINQ query into anonymous types that no-one’s talking about querying into named types, and especially into existing named types that already define constructors.  It’s just gotten passed over. 

Let’s suppose I have the canonical "AdventureWorks" sporting goods site, and I have a web page that should display a list of products in a certain category.  Let’s further suppose that my web server is sitting on the other side of a service boundary from the back-end server, perhaps using WCF or a WebService call.  I don’t want to retrieve the entirety of the products from the database and clog up the network transferring them to the web server because I’m just displaying a list, and it doesn’t need each and every little column.  I need to transfer a lighter weight "ProductSummary" object instead of the heavy "Product".

I can do a LINQ query into an anonymous type on the server-side, but how am I supposed to write a translator to turn it into my DTO?  Well, using the new type inference I could just refer to the contents of the collection as "var" and do it that way, but frankly I don’t like the look of that, and how do I type the parameter being fed in to be translated?  What if I actually NEED the ProductSummary for something on the server-side too, and would actually LIKE it to have a name?  Or what if I need to use a pre-existing ProductSummary in an existing solution?  What if that pre-existing summary object has no parameterless constructor?

Check this out:

private static void SelectIntoSummary()
{
    AdventureWorksDataContext db = new AdventureWorksDataContext();
    IEnumerable<ProductSummary> productSummaries =
        from p in db.Products
        where (p.ProductSubcategoryID == 5)
        select new ProductSummary(p.ProductID, p.Name)
        {
            CategoryName = p.ProductSubcategory.ProductCategory.Name,
            SubCategoryName = p.ProductSubcategory.Name
        };
    }
}

I was able to select into an existing object that doesn’t match the database table at all, the ProductID and Name values are passed into the constructor like normal, and I can still fill in the CategoryName and SubCategoryName properties using the new initializer syntax.  I also avoided loading extra fields from the database into the full-fledged Product object just to create a ProductSummary.

This is not news.  I have not discovered some new technique here, but I HAVE just found what I thought was a pretty interesting dark corner where none of the articles I’ve read so far have gone exploring yet.  It’s not glamorous or groundbreaking, but it is pretty cool.  And the coolest part about this is that it just worked like you’d expect it to.  LINQ is good.

I think I’m going to like the next few years.

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s