LINQ (Language Integrated Query)

C sharpLinq è un componente di .NET Framework che serve ad inviare query. Abbiamo a disposizione degli extension method C# che ci consentono di filtrare selezionare ordinare i dati. Linq è fortemente tipizzato e ci permette di interrogare diverse fonti dati purché ovviamente sia stato scritto un provider.

Linq

Linq offre una serie di extension method come Select, Where, Order by che ci consentono di interrogare elenchi. A molti di questi extension method possiamo passare come argomento una lambda expression. Un elenco è una qualsiasi classe che implementa l’interfaccia IEnumerable. Se una classe implementa tale interfaccia allora la possiamo scorrere con un ciclo foreach. Le classi che implementano IEnumerable si impegnano a fornirci tre funzionalità essenziali:

  • Di accedere sequenzialmente, cioè di scorrere in avanti l’elenco.
  • Leggere l’elemento corrente.
  • Ripartire da capo.

Vediamo innanzitutto di chiarire con un esempio di codice cosa sono gli extension method.

GLI EXTENSION METHOD

using System;
using System.Linq;
namespace Linq
{
    public class Program
    {
        static void Main(string[] args)
        {
          Azienda a = new Azienda{Denominazione="Mario Rossi",RagioneSociale="S.P.A."};
          Console.WriteLine(a.FullName());
        }
    }
    public class Azienda
    {
        private string denominazione;
        private string ragioneSociale;
        public string Denominazione
        {
            get => denominazione;
            set => denominazione=value;
        }
        public string RagioneSociale
        {
            get => ragioneSociale;
            set => ragioneSociale=value;
        }
    }
    public static class ExtensionAzienda
    {
        public static string FullName(this Azienda str)=>$"{str.Denominazione} {str.RagioneSociale}";
    }
}

Gli extension method consentono di “aggiungere” metodi ai tipi esistenti senza creare un nuovo tipo derivato, ricompilare o modificare in altro modo il tipo originale. I metodi di estensione sono metodi statici, ma vengono chiamati come se fossero metodi di istanza sul tipo Nell’esempio per creare un extension method sulla classe azienda occorre definire un metodo statico all’interno di una classe statica e usare la keyword this prima del tipo. L’extension method Where si occupa di filtrare un elenco di elementi cioè di produrre un nuovo elenco contenente un numero variabile di elementi, da 0 a tutti, in base alla nostra logica, utilizzando una lambda expression. LINQ possiede numerosi extension method. Questi sono solo alcuni:

  • Where produce un nuovo elenco contenente solo gli elementi conformi al nostro criterio di filtro;
  • Select proietta gli elementi, cioè produce un nuovo elenco i cuoi elementi sono di altro tipo;
  • Sum, Count e Average producono un valore scalare sommando, conteggiando o calcolando la media degli elementi in elenco.
Extension Method
Operatori di aggregazione

ENTITY FRAMEWORK CENNI

Linq è alla base di Entity Framework Core l’ORM di Microsoft che consente di passare dal mondo relazionale dei database a classi di entità. Un ORM (Object Relational Mapper) è una tecnologia che consente l’accesso ai dati situati in un database relazionale. I dati possono essere recuperati con query fortemente tipizzate, anziché con query SQL che sono inclini a farci commettere errori di digitazione. L’ORM si occupa di “tradurre” in SQL le nostre query fortemente tipizzate. Inoltre, legge i risultati trovati dal database e li restituisce in forma di oggetti (o grafi di oggetti) grazie a una fase che si chiama materializzazione. Un ORM è quindi uno strato di astrazione che tende ad ovviare alle rigidità del mondo relazionale e ci permette di sfruttare tutta l’espressività di un linguaggio come il C#. D’altra parte, un ORM ha un costo prestazionale proprio perché deve eseguire della logica di mapping per “adattare” le peculiarità del mondo relazionale a quelle del mondo a oggetti.

using System;
using System.Linq;
using System.Collections.Generic;
namespace Linq
{
    public class Program
    {
        static void Main(string[] args)
        {
           List<Persona> persone = new List<Persona>() {
               new Persona {Nome="Mario",Cognome="Bianchi",Eta=55,Altezza=170,Peso=80},
               new Persona {Nome="Mario",Cognome="Rossi",Eta=40,Altezza=160,Peso=80},
               new Persona {Nome="Mario",Cognome="Rossi",Eta=40,Altezza=178,Peso=85},
               new Persona {Nome="Franco",Cognome="Rossi",Eta=60,Altezza=180,Peso=70},
               new Persona {Nome="Susanna",Cognome="Verdi",Eta=25,Altezza=170,Peso=60},
               new Persona {Nome="Luigi",Cognome="Bianchi",Eta=55,Altezza=175,Peso=90}
            };
            Func<Persona, bool> myFunc = (Persona p) => p.Nome =="Mario";
            IEnumerable<Persona> pers = persone.Where(myFunc);//Abbiamo fornito il predicate che l'intellisense suggerisce.
                                  //in realta la lambda la possiamo fornire come argomento
                                  //della Where. Abbiamo specificato che vogliamo filtrare tutte
                                  //le persone il cui Nome è Mario.
            foreach(var item in pers)
              Console.WriteLine(item.Denominazione());
            /*--Adesso vogliamo selezionare tutte le persone il cui cognome è Rossi,
            selezioniamo l'eta e ne facciamo la somma.*/  
            int sum = persone.Where(z=>z.Cognome=="Rossi")
                                .Select(z=>z.Eta)
                                .Sum();//Al posto di Sum() possiamo usare il resto degli
                                       //operatori di aggregazione
            Console.WriteLine(sum);  
            //Aggiungiamo Distinct() se ci sono valori duplicati ne prende uno soltanto
             int somma = persone.Where(z=>z.Cognome=="Rossi")
                                .Select(z=>z.Eta)
                                .Distinct()
                                .Sum();
            Console.WriteLine(somma);          
            try
            {         
                //Estrazione di singoli oggetti First e Last                   
                Persona p = persone.Where(z=>z.Cognome=="Rossi")
                                    .First();//First Extension Method genera un'eccezione
                                             //se non trova valori come FirstOrDefault().
                Console.WriteLine(p.Denominazione()); 
            }  
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            } 
            try
            {                          
                Persona p = persone.Where(z=>z.Cognome=="Verdi")
                                    .Single(); //Single() ritorna un solo valore
                                               //genera un'eccezione
                                               //se trova righe duplicate.
                Console.WriteLine(p.Denominazione()); 
            }  
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            } 
            try
            {         
               //Ordinare una lista con OrderBy.                  
                IEnumerable<Persona> p = persone.Where(z=>z.Cognome=="Rossi")
                                                .OrderBy(x=>x.Peso);
                                                 
                                               
                foreach (var item in p)
                    Console.WriteLine(item.Denominazione());             
                
            }  
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            } 
            try
            {         
               //Raggruppare               
                var p = persone.GroupBy(p=>p.Cognome);;
                foreach(var item in p)
                {
                    foreach(var s in item)
                    {
                        Console.WriteLine(s.Denominazione());
                    }
                }                             
                                                 
            }  
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            } 

        }
    }
    public class Persona
    {
        private string nome;
        private string cognome;
        private int eta;
        private int altezza;
        private int peso;
        public string Nome
        {
            get => nome;
            set => nome=value;
        }
        public string Cognome
        {
            get => cognome;
            set => cognome=value;
        }
         public int Eta
        {
            get => eta;
            set => eta=value;
        }
        public int Altezza
        {
            get => altezza;
            set => altezza=value;
        }
        public int Peso
        {
            get => peso;
            set => peso=value;
        }
    }
    public static class Extension
    {
        public static string Denominazione(this Persona value)
             =>$"{value.Nome} {value.Cognome} {value.Eta}";
    }
}

LINK AI PRECEDENTI POST

LINK AL CODICE SU GITHUB