4

I have foreign table with one to many relation. I write linq query as left join equivalent and implement group by relevant id field.

from p in db.personal join pn in
  (from t in db.phoneNumbers
   group t by t.personID into g
   select new { id = g.Key, 
                number = g.Select(t => t.number), 
                prefix = g.Select(t => t.prefix) 
              }).AsEnumerable() 
  on p.ID equals pn.id 
  into lPN from lpn in lPN.DefaultIfEmpty()
//join wsd in db.basicOperations on p.ID equals wsd.personID
where p.ID == id.Value
select new partialPersonDetailsViewModel()
{
  id = id.Value,
  genderType = p.genderType,
  sPhoneNumbers="(" +lpn.prefix+") "+lpn.number
}).FirstOrDefault();

But at sPhoneNumbers="(" +lpn.prefix+") "+lpn.number this place VS notify me about error:

Error 1 Operator '+' cannot be applied to operands of type 'System.Collections.Generic.IEnumerable' and 'System.Collections.Generic.IEnumerable'

Please help me pass this error and solve problem.

loviji
  • 12,620
  • 17
  • 63
  • 94

1 Answers1

3

Both of lpn.prefix and lpn.number are evaluated as g.Select(...), so in fact they are IEnumerable<T> (exactly as error message declares it).

Evaluating them as g.Select(...).FirstOrDefault() should help you since it will extract value of type T from IEnumerable<T>.

Update:

In your case, when lpn.prefix and lpn.number are actually lists of values and you need to concatenate these lists - you can use something like:

sPhoneNumbers = String.Join("; ", 
                            lpn.prefix.Select((p, i) => 
                             String.Format("({0}){1}", 
                                            p, 
                                            lpn.numbers.Skip(i).Take(1).FirstOrDefault())));

Or you can use Enumerable.Zip method, as it was suggested in comments by @Chris:

sPhoneNumbers = String.Join("; ", 
                           lpn.prefix.Zip(lpn.numbers, 
                                         (s, s1) => string.Format("({0}){1}", s, s1)));
Andrey Korneyev
  • 26,353
  • 15
  • 70
  • 71
  • Thanks. Yes, it works when I tried FirstOrDefault(). But there is 'one to many' relation. I want return one string from phones like (12) 4589524;(077) 7090701(077) 7090701; (050) 2561024, not only (12) 4589524; – loviji Jul 14 '15 at 08:05
  • @loviji in this case you need to concatenate both lists. See updated answer. – Andrey Korneyev Jul 14 '15 at 08:19
  • For performing actions on corresponding items of two lists there is the `Zip` method. See http://stackoverflow.com/questions/7359923/adding-summing-two-arrays for a question I asked on this long ago. It saves having to manually index into the second array and thus makes it more efficient. – Chris Jul 14 '15 at 08:34
  • 1
    @Chris thank you, was not awared of `Zip` method. Looks pretty elegant. – Andrey Korneyev Jul 14 '15 at 08:41
  • Yeah. I came across it because I thought "Surely something like this must exist" and then discovered that it did. :) – Chris Jul 14 '15 at 08:59
  • @AndyKorneyev I tried to use Enumerable.Zip method. It's more easy to understand. But I've get another error like LINQ to Entities does not recognize the method `'System.String Join(System.String, System.Collections.Generic.IEnumerable 1[System.String]) method, and this method cannot be translated into a store'`. I use Npgsql EntityFramework. – loviji Jul 14 '15 at 09:14
  • @loviji you have to force your query to execute locally using `AsEnumerable`. See similar question: http://stackoverflow.com/questions/9647039/linq-cant-join-to-string – Andrey Korneyev Jul 14 '15 at 09:19
  • @AndyKorneyev many thanks. Similar question link help me understand concept. – loviji Jul 14 '15 at 12:28