2012-07-19 19 views
22

mam dane, które wygląda tak:Jak używać LINQ do wybierania do obiektu?

UserId | SongId 
-------- -------- 
1   1 
1   4 
1   12 
2   95 

Mam także następujące klasy:

class SongsForUser 
{ 
    public int User; 
    public List<int> Songs; 
} 

Co chciałbym zrobić, to użyć LINQ, aby wybrać spośród moich danych, aby stworzyć kolekcję Obiekty SongsForUser. Poniżej jest to, co mam wymyślić do tej pory:

var userCombos = songs.UserSongs.Select(x => new SongsForUser() { User = x.UserId, 
                    Songs = /*What goes here?*/ }); 

Jak bym go o wypełnianie mojej liście Songs?

Zatem wynik powinien wynosić dwa obiekty SongsForUser. Dla użytkownika 1 będzie on miał 3 pozycje na liście Songs. Dla użytkownika 2 ma on 1 pozycję na liście Songs.

Odpowiedz

36
songs.UserSongs.GroupBy(x => x.User).Select(g => new SongsForUser() 
{ 
    User = g.Key, 
    Songs = g.Select(s => s.SongId).ToList() 
}); 
+1

Dlaczego wybrać identyfikator utworu tylko w projekcji, a nie jako część grupy ? –

+1

Powoduje to błąd w części 'ToList'. Wierzę, że może tak być, ponieważ jest to Linq dla podmiotów. Błąd: 'LINQ to Entities nie rozpoznaje metody 'System.Collections.Generic.List'1 [System.String] ToList [String] (System.Collections.Generic.IEnumerable'1 [System.String])' method, oraz tej metody nie można przetłumaczyć na wyrażenie w sklepie. " –

+0

@AbeMiessler upewnij się, że masz' using System.Linq' up top. –

19

Podejrzewam chcesz:

var songsByUser = songs.UserSongs 
         .GroupBy(song => song.UserId, song => song.SongId) 
         .Select(g => new SongsForUser { User = g.Key, 
                 Songs = g.ToList() }); 

Aby wyjaśnić, po GroupBy będziesz miał kilka grup, w których kluczem każdej grupy jest identyfikatorem użytkownika, a wartości w obrębie grupę stanowią identyfikatory piosenki:

Key = 1, Values = 1, 4, 12 
Key = 2, Value = 95 

to jesteś tylko konwersja że w swoim rodzaju SongsForUser. Zauważ, że nie musisz jawnie włączać () podczas wywoływania konstruktora w inicjalizatorze obiektów - jest to niejawne, chyba że musisz podać argumenty konstruktora.

Ty mógłby to zrobić w jednym GroupBy rozmowy przy okazji:

var songsByUser = songs.UserSongs 
     .GroupBy(song => song.UserId, song => song.SongId, 
        (user, ids) => new SongsForUser { User = user, 
                Songs = ids.ToList() }); 

Osobiście zwykle znaleźć osobny Select połączenia się bardziej czytelny.

Można również zrobić to wszystko o wyrażeniu kwerendy:

var songsByUser = from song in songs.UserSongs 
        group song.SongId by song.UserId into g 
        select new SongsForUser { User = g.Key, Songs = g.ToList() }; 

EDIT: Powyżej jest „dostawcą neutralne”, ale wygląda na to, że nie działa z LINQ do podmiotów. Ci może w stanie zmusić go do pracy tak:

var songsByUser = songs.UserSongs 
         .GroupBy(song => song.UserId, song => song.SongId) 
         .AsEnumerable() 
         .Select(g => new SongsForUser { User = g.Key, 
                 Songs = g.ToList() }); 

AsEnumerable wezwanie zmusi zgrupowanie do zrobienia w bazie danych, ale ostateczna projekcja (w tym wezwanie ToList) do zrobienia lokalnie. Powinieneś jednak sprawdzić wygenerowany kod SQL pod względem wydajności.

0

Powiedzmy, że masz następujące elementy:

public class SongsForUser 
{ 
    public int UserId; 
    public List<int> Songs; 
} 

Następnie funkcja jak ten tutaj zrobi. Lista jest dostępna tylko po to, aby mieć dane do przetestowania.

public void Group() 
    { 
     List<Tuple<int, int>> SongRelations = new List<Tuple<int, int>>(); 

     SongRelations.Add(new Tuple<int, int>(1, 1)); 
     SongRelations.Add(new Tuple<int, int>(1, 4)); 
     SongRelations.Add(new Tuple<int, int>(1, 12)); 
     SongRelations.Add(new Tuple<int, int>(2, 95)); 

     var list = SongRelations.GroupBy(s => s.Item1) 
           .Select(r => new SongsForUser() 
           { 
            UserId = r.Key, 
            Songs = r.Select(t => t.Item2).ToList(), 
           }); 
    } 

list zawiera 2 elementy typu SongsForUser później. Jedna z użytkownikiem 1 i lista utworów zawierających 1, 4 i 12 i jedna z użytkownikiem 2 oraz lista utworów zawierających 95.

Powiązane problemy