\\ Home : Articoli : Stampa
LinQ to SQL
Di Acor3 (del 26/03/2008 @ 21:01:32, in DotNet, linkato 9486 volte)

LinQ nasce ovviamente per poter programmare sui classici DataBase relazionali. Tramite LinQ sono gestibili tutti i database che sono gestibili tramite Ado.Net.

Se prima la classe Connection (che sia OleDB, Odbc, Sql o Oracle) era lo strumento base con cui partire ora tutto parte da una nuova classe: la DataContext.

La DataContext si presenta come un contenitore di tutto ciò che è il DB dandoci la possibilità di accedere velocemente alle tabelle contenute nella nostra base dati per poterle dare in pasto alle nostri query con LinQ.

Per poter utilizzare la DataContext dovete innanzittutto importare una libreria nei riferimenti:

System.Data.Linq.dll.

Possiamo quindi inizializzare la nostra DataContext usando la stringa di connessione del nostro DB.

DataContext c=new DataContext(“stringa di connessione”);

Oppure utilizzare una connessione già esistente in modo da poter utilizzare sia linq che le normali funzioni di accesso.

OleDBConnection conn=new OleDBConnection(“stringa di connessione”);

DataContext c=new DataContext(connessione);

 

Ora dovete creare le classi per le tabelle presenti nel DB. Avete due possibilità: fare tutto a mano o usare la funzionalità Linq to Sql per evitarci questo noioso lavoro. Linq to Sql tuttavia non funzionerà con tutti i DB (per esempio Access) ma solo Sql Server, Sql Server Compact e SQL Server Express.

Usando i riferimenti

using System.Data.Linq;

using System.Data.Linq.Mapping;

Create classi come queste.

[Table(Name = "Persone")]

public class TabellaPersone

{

    private string nome;

    private string cognome;

    private int id;

    [Column(Name = "Id", IsPrimaryKey = true, Storage = "id")]

    public int Id

    {

        get { return id; }

        set { id = value; }

    }

    [Column(Name = "Nome", Storage = "nome")]

    public string Nome

    {

        get { return nome; }

        set { nome = value; }

    }

    [Column(Name = "Cognome", Storage = "cognome")]

    public string Cognome

    {

        get { return cognome; }

        set { cognome = value; }

    }

}

Nei tag sopra le classi ed i parametri dovrete inserire dati come il nome che ha quel campo nel DB (facoltativo se il nome coincide), se un campo è una primary key, il nome della variabile in cui è salvato il dato ed altro ancora. Potete anche specificare il tipo e se il campo può essere null o meno (esempio DbType = "Int NOT NULL").

Linq To SQL

LinQ to SQL è una procedura automatizzata per creare le nostre classi Table (il famoso data layer), praticamente un wizard. Connettetevi ad un DB tramite il menu server o createne uno. Dal menu di progetto aggiungete un nuovo elemento di tipo Linq to SQL.

Ora trascinate dal menu server le tabelle e .Net vi creerà le tabelle LinQ.

Potete vedere anche le varie forenkey associate.

Con due click avete risparmiato il dover scrivere magari decine di classi. LinQ creerà anche una classe DataContext già pronta con stringa di connessione e controlli vari.

LinQ

Quanto detto nel precedente tutorial vale anche nel caso si usi un regolare DB (lo scopo di LinQ era questo infatti). Tramite il dataContext prenderemo la tabella che ci interessa.

myDataContext.GetTable()

Questa ci restituirà la tabella con tutti gli studenti. La tabella somiglia di fatto ad una List e ci permette di iterare su di essa. Preveniamo la domanda: “Ma se la mia tabella ha 1 milione di record linq li caricherà tutti in memoria?”. La risposta è no. La tabella è un puntatore alla vera tabella nel DataBase e le righe verranno prese man mano che le chiediamo. Le query avverranno come di consueto

var data = from s in myDataContext.GetTable() where s.Nome= “Roberto” select s;

Nello scrivere query il sistema cercherà di ottimizzare al meglio la logica sottostante usando quanto più possibile il DBMS invece del sistema. Per questo alcune query che funzionano sulle liste non funzioneranno sui DB (magari perché chiedete di fare una concatenazione di stringhe dove non è supportata).

La Table contiene molte funzioni utili per effettuare chiamate base come count, max etc.

Le differenze importanti ora riguardano le operazioni di inserimento e modifica.

Modifica

Selezionate un elemento della tabella tramite query.

Studenti studente = (from s in myDataContext.getTable() where s.Matricola=matricolaSelezionata select s).First();

try

{

    studente.Nome = nuovo valore;

    studente.Cognome = nuovo valore;

    studente.Nascita = nuovo valore;

    myDataContext.SubmitChanges();

}

catch (Exception ex)

{

}

L’istruzione SubmitChanges serve per aggiornare I dati tra l’applicazione ed il database. Nel caso qualcosa non andasse restituirà una eccezione. I motivi di errore sono quelli comuni a tutti i DB: dati non corretti, problemi con chiavi esterne, errori di condizioni. Non potete comunque fare un cambiamento di chiavi primarie. Del resto sotto LinQ c’è sempre una classica Update SQL.

Inserimento

Per inserire una nuova riga si procede in questo modo.

try

{

    Studenti studente = new Studenti()

    {

        Matricola = int.Parse(txtStudentiMatricola.Text),

        Nome = txtStudentiNome.Text,

        Cognome = txtStudentiCognome.Text,

        Nascita = dateStudentiNascita.Value

    };

    //inserisce un nuovo studente

    conn.GetTable().InsertOnSubmit(studente);

    conn.SubmitChanges();

    MessageBox.Show("Ok");

}

catch (DuplicateKeyException ex)

{

    conn.GetTable().DeleteOnSubmit((Studenti)ex.Object);

    conn.SubmitChanges();

    MessageBox.Show(ex.Message);

}

L’istruzione InsertOnSubmit aggiunge un elemento alla tabella tenendolo pronto per fare l’inserimento. L’istruzione SubmitChanges provvederà all’inserimento definitivo. Attenzione, qui c’è un qualcosa di delicato da gestire. Nel caso l’inserimento non vada a buon fine sarà necessario rimuovere la l’oggetto dalla tabella. Altrimenti ad ogni SubmitChanges verrà di nuovo restituito l’errore.

Il motivo di questo è semplice.

Se un oggetto inserito non è valido potrebbe essere preferibile mantenere l’oggetto e correggere solo il campo errato. In questo caso basta modificare il campo non valido e procedere ad un nuovo Submit. Se invece, come nell’esempio, si vuole annullare l’operazione, allora si elimina l’oggetto incriminato. L’eccezione contiene già l’oggetto che è duplicato nella tabella. Altri tipi di eccezione diversi da campi duplicati vengono gestiti tramite l’eccezione ChangeConflictException simile alla precedente. Nel caso di eccezioni diverse dovrete voi conservare la classe incriminata ed eliminarla dalla tabella). Sarebbe comunque buona norma che non si verifichino errori di chiavi esterne non valide.

Vi lascio ad un piccolo esempio che utilizza un DB Sql Server Express per simulare un libretto elettronico degli esami.

Demo