LINQ (Language-Integrated Query) rappresenta un set di funzionalitΓ introdotto in Visual Studio 2008 che migliora la gestione delle query nella sintassi dei linguaggi C# e Visual Basic.
Select
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
var numQuery =
from num in numbers
where (num % 2) == 0
select num;
//L'esecuzione della query avviene qui!
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
La variabile di query numQuery non esegue mai una query, questa viene effettivamente eseguita solo quando la query viene chiamata. Tale variabile Γ¨ di tipo IEnumerable<T>, quindi facilmente ciclabile con un foreach.
Funzioni di aggregazione
Alla variabile di query posso applicare funzioni di aggregazione, come Count, Max, Average e First. Queste istruzioni eseguono la query e restituiscono un solo valore, non un IEnumerable.
int evenNumCount = numQuery.Count();
Esecuzione immediata
Se voglio eseguire immediatamente una query e salvare i risultati in cache conviene utilizzare il metodo ToArray();.
var numQuery3 =
(from num in numbers
where (num % 2) == 0
select num).ToArray();
Esempi
Creazione della sorgente dei dati
Creiamo la sorgente dei dati:
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
}
// Create a data source by using a collection initializer.
static List<Student> students = new List<Student>
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}},
new Student {First="Claire", Last="O'Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
new Student {First="Michael", Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91} }
};
Studenti il cui punteggio nel primo test era superiore a 90
IEnumerable<Student> studentQuery =
from student in students
where student.Scores[0] > 90 && student.Scores[3] < 80
select student;
Si noti che, poichΓ© viene selezionato lβintero oggetto Student (select student
) il tipo della query Γ¨ quindi IEnumerable<Student>
.
Se io facessi invece select student.Last
(che Γ¨ una stringa), il tipo della query sarebbe IEnumerable<string>
.
Per eseguire la query Γ¨ necessario scrivere il ciclo foreach
foreach (Student student in studentQuery)
{
Console.WriteLine("{0}, {1}", student.Last, student.First);
}
Ordinamento dei risultati
SarΓ piΓΉ semplice analizzare i risultati se vengono ordinati. Γ possibile ordinare la sequenza restituita in base a qualsiasi campo accessibile negli elementi di origine. Ad esempio, la clausola orderby riportata di seguito ordina i risultati alfabeticamente dalla A alla Z in base al cognome di ogni studente. Aggiungere alla query la clausola orderby, subito dopo lβistruzione where e prima dellβistruzione select:
orderby student.Last ascending
Raggruppamento dei risultati
Il raggruppamento Γ¨ una funzionalitΓ potente nelle espressioni di query. Una query con una clausola group genera una sequenza di gruppi e ogni gruppo contiene un oggetto Key e una sequenza costituita da tutti i membri di tale gruppo. Nella nuova query riportata di seguito gli studenti vengono raggruppati utilizzando la prima lettera del cognome come chiave.
var studentQuery2 =
from student in students
group student by student.Last[0];
Il tipo della query Γ¨ stato ora modificato. Vengono ora generate una sequenza di gruppi con il tipo char come chiave e una sequenza di oggetti Student. PoichΓ© il tipo della query Γ¨ stato modificato, nel codice seguente viene modificato anche il ciclo di esecuzione foreach:
foreach (var studentGroup in studentQuery2)
{
Console.WriteLine(studentGroup.Key);
foreach (Student student in studentGroup)
{
Console.WriteLine("{0}, {1}", student.Last, student.First);
}
}
Utilizzare le variabili in modo implicito
Codificare in modo esplicito IEnumerables di IGroupings puΓ² risultare noioso. Γ possibile scrivere la stessa query e il ciclo foreach in modo notevolmente piΓΉ pratico utilizzando var. La parola chiave var non modifica i tipi degli oggetti ma indica solo al compilatore di dedurre i tipi.
Ordinare i gruppi in base al valore della chiave
Quando si esegue la query precedente, i gruppi non sono in ordine alfabetico. Per modificare questo comportamento, Γ¨ necessario fornire la clausola orderby dopo la clausola group. Per utilizzare la clausola orderby, Γ¨ necessario perΓ² utilizzare prima un identificatore che funga da riferimento ai gruppi creati dalla clausola group. Fornire lβidentificatore utilizzando la parola chiave into, come segue:
var studentQuery4 =
from student in students
group student by student.Last[0] into studentGroup
orderby studentGroup.Key
select studentGroup;
Γ possibile utilizzare la parola chiave let per introdurre un identificatore per qualsiasi risultato dellβespressione di query. Questo identificatore puΓ² risultare utile come nellβesempio seguente o puΓ² migliorare le prestazioni archiviando i risultati di unβespressione in modo da non doverla calcolare piΓΉ volte.
var studentQuery5 =
from student in students
let totalScore = student.Scores[0] + student.Scores[1] +
student.Scores[2] + student.Scores[3]
where totalScore / 4 < student.Scores[0]
select student.Last + " " + student.First;
foreach (string s in studentQuery5)
{
Console.WriteLine(s);
}
Gestione dei valori di ritorno delle SP
FirstOrDefault()
Restituisce il primo elemento di una sequenza o un valore predefinito se la sequenza non contiene elementi. Da usare (quasi sempre) quando ho un solo record di ritorno da una SP.
Single()
Restituisce il singolo elemento di una sequenza e genera unβeccezione se nella sequenza non Γ¨ presente esattamente un elemento.
SingleOrDefault()
Restituisce il singolo elemento di una sequenza o un valore predefinito se la sequenza Γ¨ vuota; questo metodo genera unβeccezione se esiste piΓΉ di un elemento nella sequenza.
toList()
Crea un oggetto List<T> da un oggetto IEnumerable<T>. Da usare quando una SP restituisce piΓΉ di un record.
Lamda syntax
Come parametro in ingresso alle funzioni linq (principalemente firstOrDefault()) posso scrivere delle lamda espressioni. Assumendo di avere il seguente array:
string[] names = { "Tom", "Dick", "Harry", "Mary", "Jay" };
La seguente espressione
string query =
names.FirstOrDefault (name => name.EndsWith ("y"));
indica:
- FirstOrDefault(): voglio solo un elemento
name => name.EndsWith ("y")
lβelemento che voglio deve terminare per βyβ. Γ¨ la stessa cosa della sintassi di rubyarray.map{|a| a.ends_with("y")}
. Invece di βnameβ posso scrivere anche βnβ o quello che voglio, serve come riferimento per lβesecuzione della lamda espressione.
Il risultato sarΓ infatti:
string query = "Harry"
Allo stesso modo se cambio lβespressione in:
IEnumerable<string> query =
names.Where (name => name.EndsWith ("y"));
Ottengo:
string[] names = { "Harry", "Mary", "Jay" };
Esempi
Ho la seguente SP che mi ritorna un elenco di AidMotivoReclamo
(funzione ToList()
)
var aidReclami = connection.Query<AidMotivoReclamo>("Selfcare.GetAIDIndiciConfig", new { IdMotivo = idMotivo, IdReclamoPubblicazione = idReclamoPubblicazione }, commandType: CommandType.StoredProcedure).ToList();
Controllare se esiste un record con un determinato campo valorizzato
Voglio vedere se esiste almeno un aidReclami
che abbia il campo XMLConfig_Aid
con un valore non nullo
if (aidReclami.Any(r => !string.IsNullOrEmpty(r.XMLConfig_Aid)))
Selezionare il primo record che ha un determinato campo valorizzato
Allo stesso modo di prima ho:
var aid = aidReclami.FirstOrDefault(r => !string.IsNullOrEmpty(r.XMLConfig_Aid));
Ciclare tutti i valori che hanno una determinata caratteristica
foreach (var aid in aidReclami.Where(aid => !string.IsNullOrEmpty(aid.SqlDropDown))){}
Ticket.Fields
var List<UtilityItem> ticket.Fields
con UtilityItem
formato da string Codice
e string Descrizione
UtilityItem itemToCheck = ticket.Fields.SingleOrDefault(f =>f.Descrizione.Equals("test");