Home > C#, Extension Methods, LINQ > Use SelectExcept When You Are Too Lazy To Type

Use SelectExcept When You Are Too Lazy To Type

Do you love LINQPad?  Use it every day?  Do ad-hoc queries non-stop against your DataContexts?  Love C#/LINQ’s ability for anonymous object projections into new forms?  I’m assuming you said yes to all those.  Here is the question that drives this post…do you hate having to type *every* field *except* one (or a few) when you *only* need almost all fields?  If you answered yes to that last question or are wondering why I don’t just allow the entire row to be selected/returned, continue reading…

Before I get into the meat of this post, I’m assuming you are probably familiar with my LinqToSql Extensions I use daily in LINQPad and I want to note just a few improvements to my L2S library since my last post.

  1. Changed the DumpCSV method to behave more like LINQPad’s own Dump method; it returns the same object that was passed in, allowing for additional LINQ statements to be chained on after any calls to DumpCSV.
  2. Changed DumpCSV to be a static method available on IEnumerable objects instead of only IQueryable.  Not sure why I chose IQueryable to start with, but there have been several times when I’ve wanted to dump an IEnumerable to CSV and had to first call .AsQueryable() before I could use my extension – too many keystrokes.
  3. I updated the UpdateBatchPreview and DeleteBatchPreview statements to first dump out a count of records to be affected before dumping out the generated SQL.

I hope those little updates help you as much as they’ve helped me (in their own small ways).

I’m not sure how I’ll try to promote this post because I think its core point has hard search terms to describe in Google (at least for me it did).  So I don’t think Google searches are going to get people to this post, but we’ll see.  If you search for LINQ, SelectExcept, Select All Fields Except, etc. you get flooded with results referencing LINQ’s built in Except method or people trying to figure out how to use an equivalent for TRANSACT SQL’s NOT IN (which by the way is !array.Contains( field )).  No, the core point of this post is creating an extension that allows you to specify a selector Expression the same way you would in LINQ’s default Select method, but instead of selecting those fields you specified, it skips the fields from the selector expression and selects *all other fields*!

You might be asking yourself, “Does it really matter if you skip one or two fields?”  Well as any of you who have read any of my previous posts know, I use LINQPad everyday.  Several of my tables I deal with have lots of columns – and often one (or few) of these columns is a ‘details’ column that inevitably contains lots of linefeeds.  So if you want to see a list of 50+ items, you probably know what LINQPad’s Dump method does.  Below is a screen shot of a simple query against a ASP.Net HealthMonitoring WebEvents table to list first 50 errors:

var errorTypes = 
     new [] { "System.Web.Management.WebRequestErrorEvent", 
    "BTR.Web.MadHatter.Mvc.Management.UnhandledErrorEvent", 
    "System.Web.Management.WebErrorEvent", 
    "BTR.Web.MadHatter.Mvc.Management.BtrWebBaseEvent" };

WebEvents.Where( e => errorTypes.Contains( e.weEventType ) )
         .Take( 50 )
         .Dump();

LINQPad displays something like this:

image

As you can see, I can only see one row of results at a time because the detail column (not even shown on the screen) is requiring lots of vertical space to render.  The problem with this, as any veteran LINQPad user would know, is that once you start scrolling, since the column headers have disappeared, if you have both lots of columns and column( s ) with lots of line feed data, it is very easy to ‘lose track of which row/column’ you are looking at.  Who’s familiar with a view similar to this?

image

In addition to the ‘detail’ column, if you are familiar with the HealthMonitoring table schema, you know that there are ‘db key’ fields, some time stamp fields, URL request info fields, etc.  More columns than I could shake a stick at.  What if I just wanted a dump of ‘when errors happened, who caused them, and what page they were visiting’ and I didn’t really care about error details or the low level HealthMonitoring fields?  I could do a query like the following and get a dump from LINQPad as follows:

WebEvents.Where( e => errorTypes.Contains( e.weEventType ) ).Take( 50 )
         .Select( e => new { 
                 e.weClient, 
                e.weAuthId, 
                e.weImpersonatingAuthId, 
                e.weIPAddress, 
                e.weUserName, 
                e.weEventTime, 
                e.weEventType, 
                e.weExceptionType, 
                e.weMessage,
                e.weApplicationPath,
                e.weApplicationVirtualPath,
                e.weRequestUrl } )
         .Dump();

 

image

Ah, *much* nicer!  I’ve improved my output amount by 600% even after decreasing the size of the result window (to show LINQ query).  The only downside to this is all the typing I have to do for the Select method.  I only want to weed out just a few columns, all that typing is too many keystrokes!  With SelectMany(), you can accomplish the same thing with the following:

WebEvents.Where( e => errorTypes.Contains( e.weEventType ) ).Take( 50 )
         .SelectExcept( e => new { 
                e.weEventId, 
                e.weEventTimeUtc, 
                e.weDetails } ).Dump();

Your fingers are thanking me already!  There is one slight downfall to the code.  Internally, it uses the Select( string selector ) extension method from System.Linq.Dynamic library (as described by Scott Guthrie here) and similarly only returns an IQueryable of an unknown anonymous type, so you can not chain on additional LINQ functions that require selector or predicate parameters.  Even with this drawback, I’m loving the number or keystrokes I save when I just need simple dumps of tables and want to exclude an ‘additional info’ column so LINQPad’s default rendering is concise and clear as it can be.  Other tables with just one column to exclude is where this extension really shines.  Consider the following, where you don’t even need the new { } anonymous type declaration!

Processes.Take( 50 ).SelectExcept( p => p.procData ).Dump();

As always, the code can be found here.  If you are as lazy as me and want to save your keystrokes, do yourself a favor and get this.  Then use some of those saved keystrokes to leave a comment below letting me know any other improvements or features you’d like to see in my L2S extensions.

Advertisements
Categories: C#, Extension Methods, LINQ
  1. No comments yet.
  1. No trackbacks yet.

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

%d bloggers like this: