Pages

Saturday, January 21, 2012

LINQ Tips : Writing D.R.Y. LINQ

What good is LINQ to entities if you have to write your C# logic and then repeat it in another place as "will become SQL" logic?  Having to update the same logic in multiple places to add a feature to your codebase is highly undesirable; so much so that it even has a name.

Luckily, the ADO.NET team  asked the same question and, in this post, we'll make sure you're writing LINQ to Entities code as unlike inline SQL as possible and try to break our query down into reusable pieces.

Let's consider a simple scenario : 

You have a book store management website.  On one page, you're displaying every single book that has a genre.  Then, on another page, you're displaying every single book and adding a button  next to the record to add a genre if there isn't one.

Here's our data model
Here's what you shouldn't do :



It looks innocent enough, but why must our logic for determining whether a book has a genre or not be baked into our .Where call?  Is this really the best we can do?  How can we combine that logic with other queries that also check if a book lacks a genre.

Here's what you should do :


And our helper method looks like this.  








This was all done so that we could do this in our view (The second place we need to execute this logic--only this time we need to actually extract the Func<Book, bool> by compiling it into CIL.  The way we do this is by calling Compile() which will recurse through our expression tree and produce the actual CIL we want--we then simply invoke it.

We should have written another wrapper for this invoke call to make another nice helper, but I don't want to drown the reader in screenshots.

(The model is a list of Book)

At this point we should be ecstatic!  We've managed to keep the logic of determining an empty genre outside of the view entirely!   And we've already "composed" our Books() method with the BookHasNoGenre method to accomplish a single task.

Here's the page fully rendered :







Conclusion

Hopefully, you've been convinced that it's a good idea to avoid repeating yourself and that you CAN, in fact, write D.R.Y. LINQ to entities code that isn't just inline SQL in disguise.

I will post the code if anyone requests it.