6

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?

LiamB
  • 18,243
  • 19
  • 75
  • 116

4 Answers4

7

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
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @Jon SKeet - Thanks for the reply. Adding the .ToList() results int he same error. (Just on that line now rather than at the VIEW) – LiamB May 25 '10 at 15:14
  • @Jon Skeet - Sneeky suspicion that this is to do with SubSonic. As I make no actual call to .First(); – LiamB May 25 '10 at 15:34
  • @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? – LiamB May 25 '10 at 15:43
  • @Pino: its weird. sorry for _bad_ suggestions – cem May 25 '10 at 15:49
  • @cem dont be sorry it wasnt bad, i appriciate you trying to help! – LiamB May 25 '10 at 16:07
2

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
  • 1,911
  • 12
  • 16
  • as I said, I am not directly calling that. This seems to be deep in the subsonic files. Maybe thats causing the issue? – LiamB May 25 '10 at 15:35
  • yep. its why this happening. edit. maybe using try catch statements'll fix this. did you tried? – cem May 25 '10 at 15:40
0
this.ProductOptions.Select(o => o.ToDataModel()).ToList<ProductOptionModel>();
Kevin Le - Khnle
  • 10,579
  • 11
  • 54
  • 80
-1

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();
Kevin Le - Khnle
  • 10,579
  • 11
  • 54
  • 80