2015-07-02 4 views
6

Ho una tabella users:tavoli associare utilizzando valori di riga come colonna LINQ C# SQL

Id | Name | Age 
-------------------- 
1 | Steve | 21 
2 | Jack | 17 
3 | Alice | 25 
4 | Harry | 14 

ho anche una tabella contenente informazioni aggiuntive utente:

UId | Key | Value 
---------------------- 
1 | Height | 70 
2 | Height | 65 
2 | Eyes | Blue 
4 | Height | 51 
3 | Hair | Brown 
1 | Eyes | Green 

I UId link di colonna per il Id colonna nella tabella users. Come puoi vedere, non tutti gli utenti hanno le stesse informazioni aggiuntive presenti. Alice non ha un valore di altezza, Jack è l'unico con un valore di colore degli occhi ecc.

C'è un modo per combinare questi dati in una tabella in modo dinamico utilizzando le query C# e LINQ in modo che il risultato sia qualcosa come questo :

Id | Name | Age | Height | Eyes | Hair 
------------------------------------------ 
1 | Steve | 21 | 70 | Green |  
2 | Jack | 17 | 65 | Blue |  
3 | Alice | 25 |  |  | Brown 
4 | Harry | 14 | 51 | 

Se un utente non ha un valore per la colonna, può rimanere vuoto/nullo. Questo richiede una sorta di dati pivoting?

+1

controllo questo ti aiuterà http://stackoverflow.com/questions/14066679/using-piv ot-table-in-linq –

+0

La tabella delle informazioni utente aggiuntiva è costante o le nuove chiavi dovrebbero sempre essere possibili senza modificare il LINQ? – Matt

+0

Pensi di nasconderti dopo aver rimosso l'anwer downvoted? Lo Stackoverflow è già stato notificato per la tua attività con qualsiasi dettaglio. Questo non è un posto dove giocare, è un posto dove imparare e condividere le tue conoscenze. –

risposta

3

Per il caso, i campi informazioni utente sono costanti:

var result = users.GroupJoin(details, 
      user => user.Id, 
      detail => detail.Id, 
      (user, detail) => new 
      { 
       user.Id, 
       user.Name, 
       user.Age, 
       Height = detail.SingleOrDefault(x => x.Key == "Height").Value, 
       Eyes = detail.SingleOrDefault(x => x.Key == "Eyes").Value, 
       Hair = detail.SingleOrDefault(x => x.Key == "Hair").Value, 
      }); 
+0

Grazie per la risposta! Mentre c'erano alcune risposte che producevano i risultati desiderati, la tua era la più semplice secondo me. –

+0

Ma attenzione se sono possibili più valori di UId/chiave. Quindi dovresti usare FirstOrDefault o LastOrDefault. – Matt

+0

Sì, in realtà è la situazione esatta che ho. Sono possibili più UId, quindi ho usato 'FirstOrDefault'. Grazie ancora! –

0

Prova questa ricerca

var objlist=(form a in contex.user 
       join b in contex.UserDetails on a.id equals a.Uid into gj 
       from subpet in gj.DefaultIfEmpty() 
         select new { Id=a.id, Name=a.name, Age=a.age, Height =subpet.Height,Eyes=subpet.Eyes, Hair=subpet.Hair}).ToList(); 
+1

Sulla riga 2, si suppone che sia 'da b in' anziché' da b in' perché ottengo un errore di sintassi usando 'into'. Ricevo anche un errore nella parte 'join' che dice 'espressione non valida' join''. Grazie per la risposta! –

+0

Ok ora controlla. No dire grazie dato il giusto segno di interrogazione e voto –

+0

Dove sono finiti i beni immobili.Altezza, subpet.Eyes, subpet.Hair vieni? Questa query non funzionerà. –

2

è possibile farlo utilizzando GroupJoin, ad esempio:

var users = new List<Tuple<int, string, int>> { 
    Tuple.Create(1, "Steve", 21), 
    Tuple.Create(2, "Jack", 17), 
    Tuple.Create(3, "Alice", 25), 
    Tuple.Create(4, "Harry", 14) 
}; 
var userInfos = new List<Tuple<int, string, string>> { 
    Tuple.Create(1, "Height", "70"), 
    Tuple.Create(2, "Height", "65"), 
    Tuple.Create(2, "Eyes", "Blue"), 
    Tuple.Create(4, "Height", "51"), 
    Tuple.Create(3, "Hair", "Brown"), 
    Tuple.Create(1, "Eyes", "Green"), 
}; 
var query = users.GroupJoin(userInfos, 
    u => u.Item1, 
    ui => ui.Item1, 
    (u, infos) => new { User = u, Infos = infos }); 
var result = query.Select(qi => new 
{ 
    Id = qi.User.Item1, 
    Name = qi.User.Item2, 
    Age = qi.User.Item3, 
    Height = qi.Infos.Where(i => i.Item2 == "Height").Select(i => i.Item3).SingleOrDefault(), 
    Eyes = qi.Infos.Where(i => i.Item2 == "Eyes").Select(i => i.Item3).SingleOrDefault(), 
    Hair = qi.Infos.Where(i => i.Item2 == "Hair").Select(i => i.Item3).SingleOrDefault() 
}); 
+0

Puoi spiegare cosa sono 'Item1',' Item2' e 'Item3'? Perché ho notato che non sono dichiarati da nessuna parte. Grazie per la risposta! –

+1

@Reece Kenney Queste sono le proprietà di una classe ['Tuple'] (https://msdn.microsoft.com/en-us/library/system.tuple (v = vs.110) .aspx) che viene utilizzata per crea gli elementi di 'utenti' e' utenteInfos'. Ad esempio, nel caso di un elemento 'users',' Item1' si riferisce all'Id, 'Item2' si riferisce al Nome e così via. – Dzienny

1

Prova questa

var list = (from u in context.users 
         join ud in context.UserDetails on u.Id equals ud.UId 
         select new 
         { 
          u.Id, 
          u.Name, 
          u.Age, 
          ud.Key, 
          ud.Value 
         }); 

      var finallist = list.GroupBy(x => new { x.Id, x.Name,x.Age}).Select(x => new 
       { 
        x.Key.Id, 
        x.Key.Name, 
        x.Key.Age, 
        Height = x.Where(y => y.Key == "Height").Select(y => y.Value).FirstOrDefault(), 
        Eyes = x.Where(y => y.Key == "Eyes").Select(y => y.Value).FirstOrDefault(), 
        Hair = x.Where(y => y.Key == "Hair").Select(y => y.Value).FirstOrDefault() 
       }).ToList(); 
2

Prima di tutto ho raggruppato i dati dettagli utente utilizzando la funzione (ho rinominato la proprietà Key con Feature per evitare confusione) & UId quindi ho usato il join di gruppo per combinare entrambi i risultati usando into g. Finalmente recuperato il risultato utilizzando la funzionalità specificata.

var result = from user in users 
      join detail in details.GroupBy(x => new { x.UId, x.Feature }) 
      on user.Id equals detail.Key.UId into g 
      select new 
     { 
      Id = user.Id, 
      Name = user.Name, 
      Age = user.Age, 
      Height = g.FirstOrDefault(z => z.Key.Feature == "Height") != null ? 
       g.First(z => z.Key.Feature == "Height").First().Value : String.Empty, 
      Eyes = g.FirstOrDefault(z => z.Key.Feature == "Eyes") != null ? 
       g.First(z => z.Key.Feature == "Eyes").First().Value : String.Empty, 
      Hair = g.FirstOrDefault(z => z.Key.Feature == "Hair") != null ? 
       g.First(z => z.Key.Feature == "Hair").First().Value : String.Empty, 
     }; 

sto ottenendo seguente output: -

enter image description here

Ecco la completa Working Fiddle.