views:

143

answers:

4

Ok I have the following, set-up and working great. These lines of code should do a conversion from DAL Entity (Subsonic) to a ViewModel.

    IList<ProductOptionModel> OptionsRetData = new List<ProductOptionModel>();

    foreach (var CurProductOption in this.ProductOptions)
    {
        OptionsRetData.Add(CurProductOption.ToDataModel());
    }

    returnData.Options = OptionsRetData.AsEnumerable();

I'd like to convert this to a LINQ single line statment and came up with the following.

returnData.Options = this.ProductOptions.Select(o => o.ToDataModel());

and am recieving the following error.

Server Error in '/' Application.
Sequence contains no matching element 

So why does the first statment work but not the LINQ and, what steps can I take to resolve it.

Stack Trace

at System.Linq.Enumerable.First[TSource](IEnumerable1 source, Func2 predicate) at SubSonic.Extensions.Database.Load[T](IDataReader rdr, T item, List1 ColumnNames) at SubSonic.Extensions.Database.ToEnumerable[T](IDataReader rdr, List1 ColumnNames) at SubSonic.Linq.Structure.DbQueryProvider.Execute[T](QueryCommand1 query, Object[] paramValues) at lambda_method(Closure ) at SubSonic.Linq.Structure.DbQueryProvider.Execute(Expression expression) at SubSonic.Linq.Structure.Query1.GetEnumerator()

Maybe this is to do with subsonic?

+6  A: 

One possibility is that it's not working because you've changed the time at which the query is materialized. Change the code to this instead:

returnData.Options = this.ProductOptions.Select(o => o.ToDataModel()).ToList();

That will force the query to be evaluated at the same time it was before.

EDIT: Your stack trace is showing First() being called somehow, but we haven't got anything about that in the code you've shown... any ideas where that's happening?

EDIT: I've realised the difference - and I'm foolish for not doing so before. You want to force the projection to be done in-process:

returnData.Options = this.ProductOptions
                         .AsEnumerable()
                         .Select(o => o.ToDataModel())
                         .ToList();

That extra call to AsEnumerable means it'll be the Enumerable.Select overload which gets called, making it equivalent to your original code.

Jon Skeet
@Jon SKeet - Thanks for the reply. Adding the .ToList() results int he same error. (Just on that line now rather than at the VIEW)
Pino
@Jon Skeet - Sneeky suspicion that this is to do with SubSonic. As I make no actual call to .First();
Pino
@Pino: I have another idea. Editing now...
Jon Skeet
@Jon Skeet - There is a reason you have such a high rep. Thanks again, this worked. Is there anywhere I can read up a little more about what you have written?
Pino
@Pino: its weird. sorry for _bad_ suggestions
cem
@cem dont be sorry it wasnt bad, i appriciate you trying to help!
Pino
A: 
this.ProductOptions.Select(o => o.ToDataModel()).ToList<ProductOptionModel>();
Khnle
@Khnle - Same problem when using the example line.
Pino
A: 

I think you have to check for the length of this.ProductOptions before the LINQ statement.

So maybe (revised without check for null):

returnData.Options = (this.ProductOptions.Length > 0) ? this.ProductOptions.Select(o => o.ToDataModel()) : new List<ProductOptionModel>().AsEnumerable();
Khnle
@Khnle Why does the loop work then?
Pino
Maybe no need to check for null. The loop works because with length 0, the flow of the program never enters the loop.
Khnle
Select shouldn't fail if it doesn't get any values though... it should just yield an empty result.
Jon Skeet
+2  A: 

As i said you're using First method. you may want to change it to FirstOrDefault. it will be solved. or do you able to change?

Stack Trace

at System.Linq.Enumerable.First

cem
@cem as I said, I am not directly calling that. This seems to be deep in the subsonic files. Maybe thats causing the issue?
Pino
yep. its why this happening. edit. maybe using try catch statements'll fix this. did you tried?
cem
@cem, see Jon Skeets Answer.
Pino