Long Cloud Technologies
"... A Yankee in the Land of the Long White Cloud, Aotearoa ..."

Linq odd behavior and the need for a .ToList() [where I suspect there shouldn’t be any need]

Give an Entity Frameworks model that has an EmployerUsers table, in which there are two columns, Guid and Name  Consider this code…

List<SelectListItem> employerUserSelectList = new List<SelectListItem>( );

var employerUsers = dal.EmployerUsers.Where( eu => eu.EmployerGuid == SecurityHelpers.EmployerGuid );

employerUserSelectList.Add( new SelectListItem( ) { Text = " [ Select TeamMember ] " , Value = Guid.Empty.ToString( ) } );

employerUserSelectList.AddRange(
   employerUsers.ToList( ).Select(
      eu => new SelectListItem( )
      {
         Text = eu.Name ,
         Value = eu.Guid.ToString( )
      }
   )
);

The important piece of code I want you to really look at is this:

 

employerUsers.ToList( ).Select(
   eu => new SelectListItem( )
   {
      Text = eu.Name ,
      Value = eu.Guid.ToString( )
   }
)

now compare that with this…

employerUsers.Select(
   eu => new SelectListItem( )
   {
      Text = eu.Name ,
      Value = eu.Guid.ToString( )
   }
)

Would you or would you not expect these to both work exactly the same?  Well I would but if you try to run the code with the second clause you get the following error

image

System.NotSupportedException was unhandled by user code
  Message=LINQ to Entities does not recognize the method 'System.String ToString()' method, and this method cannot be translated into a store expression.
  Source=System.Data.Entity
  StackTrace:
		...SNIP...
  InnerException: 

Yeah, pretty weird, you have to add the .ToList() to coalesce the IQueryable into an IEnumerable BEFORE you call the .Select.

I think this is a bug, either the .Select shouldn’t be allowed on the IQueryable if it can’t handle it, or it should be smart enough to do the .ToList() if necessary.

Your Thoughts?

You can reach me on Twitter at @matthewhintzen:  http://twitter.com/matthewhintzen

Posted on 26 Aug 10 22:58 by matthew.hintzen |

Bookmark this post with:

E-mail | Comments(0) | Comment RSS


With Linq you too can program like C++ programmer (if a line of code doesn’t confuse, it’s not doing enough)

I don’t know if you ever had the opportunity to attend those old time geek fests where after the days conferences and presentations, the programmers would gather for drinks and a little after hours friendly competitions, but they were fun, and sometimes really scary.  One of my favorite was to attend a contest where C++ programmers would be given a programming task and the team that produced the lowest total sum of number of semi-colons plus number of programming structures won.

In case you’re not sure what that means exactly, it means who could do the most stuff on the least lines of code.  Get as much processing into a single line of code.  And in C++ you canREALLY do a lot of work in a single line of code if you know what you were about; Mind you the line could end up being 400 characters in length, and completely impossible to figure out what it was doing in retrospect, but damn it was concise!

Needless to say BASIC (and it’s variant Visual Basic) definitely DIDN’T have that capability.  I come from a VB background, and while you can get ridiculous in C#, my coding habits from my VB days means I generally don’t go for obtuse line coding.  In fact one of my mantras is “One line of code, should only do One thing.”

But then along comes Linq, which just BEGS you to do many things in one line, and before you know it you start figuring out how to combine.  And there is this urge to just “combine a little bit more” and before you know it, a C++ programmer would be willing to buy you a beer for your ability to product obtuse, obscure, confusing code.

_Events = Claim.Events
 .OfType<Wizard>( )
 .Where(
 w => w.StatusType == ( int )Enums.EventWizardStatusType.Open || w.StatusType == ( int )Enums.EventWizardStatusType.InProgress )
 .Cast<Event>( )
.Union( Claim.Events .OfType<Task>( )
 .Where( w => w.StatusType == ( int )Enums.TaskStatusType.Open || w.StatusType == ( int )Enums.TaskStatusType.InProgress )
 .Where( w => w.Tasks.Count == 0 )
 .Cast<Event>( ) ).OrderBy( e => e.DueDate ).ToList( );

Ok quick can you tell at a glance what that does?  No, neither could I, after I had finished compressing four statements into one.  It was really cool what I had achieved, but when the day comes that I need to modify that code, and trust me the day will come, I would curse myself.  So even though it means I have to hand in my Obfuscated Code Black Belt, I decided to go with instead the following (which is functionally equivalent to the preceding).

var wizards = Claim.Events
 .OfType<Wizard>( )
 .Where( w => w.StatusType == ( int )Enums.EventWizardStatusType.Open || w.StatusType == ( int )Enums.EventWizardStatusType.InProgress )
 .Cast<Event>( ); 

var tasks = Claim.Events
 .OfType<Task>( )
 .Where( w => w.StatusType == ( int )Enums.TaskStatusType.Open || w.StatusType == ( int )Enums.TaskStatusType.InProgress ) .Where( w => w.Tasks.Count == 0 )
 .Cast<Event>( ); 

var events = tasks.Union( wizards ); 

_Events = events.OrderBy( e => e.DueDate ).ToList( ); 
Posted on 11 Jun 10 22:31 by matthew.hintzen |

Bookmark this post with:

E-mail | Comments(0) | Comment RSS