Configurazione delle impostazioni del livello di accesso ai dati a livello di connessione e di comando (C#)

di Scott Mitchell

Scarica il PDF

Gli oggetti TableAdapter all'interno di un dataset tipizzato si occupano automaticamente della connessione al database, dell'emissione di comandi e del popolamento di un oggetto DataTable con i risultati. Tuttavia, in questa esercitazione viene illustrato come accedere alle impostazioni a livello di database e a livello di comando in TableAdapter.

Introduzione

Nell'intera serie di esercitazioni sono stati usati set di dati tipizzati per implementare il livello di accesso ai dati e gli oggetti business dell'architettura a più livelli. Come illustrato nella prima esercitazione, le tabelle DataTable del set di dati tipizzato fungono da repository di dati, mentre gli oggetti TableAdapter fungono da wrapper per comunicare con il database per recuperare e modificare i dati sottostanti. Gli oggetti TableAdapter incapsulano la complessità dell'uso del database e consentono di scrivere codice per connettersi al database, eseguire un comando o popolare i risultati in una tabella DataTable.

In alcuni casi, tuttavia, quando è necessario scavare nelle profondità dell'oggetto TableAdapter e scrivere codice che funziona direttamente con gli oggetti ADO.NET. Nell'esercitazione Wrapping delle modifiche del database all'interno di una transazione, ad esempio, sono stati aggiunti metodi a TableAdapter per iniziare, eseguire il commit e il rollback delle transazioni ADO.NET. Questi metodi utilizzavano un oggetto creato SqlTransaction manualmente e interno assegnato agli oggetti TableAdapter SqlCommand .

In questa esercitazione verrà illustrato come accedere alle impostazioni a livello di comando e connessione del database in TableAdapter. In particolare, si aggiungeranno funzionalità a ProductsTableAdapter che consente l'accesso alle impostazioni di timeout del stringa di connessione e dei comandi sottostanti.

Uso dei dati tramite ADO.NET

Microsoft .NET Framework contiene un'ampia gamma di classi progettate appositamente per lavorare con i dati. Queste classi, trovate all'interno delloSystem.Data spazio dei nomi, vengono definite classi ADO.NET. Alcune classi sotto l'ombrello ADO.NET sono associate a un provider di dati specifico. È possibile considerare un provider di dati come un canale di comunicazione che consente il flusso delle informazioni tra le classi ADO.NET e l'archivio dati sottostante. Esistono provider generalizzati, come OleDb e ODBC, nonché provider appositamente progettati per un particolare sistema di database. Ad esempio, sebbene sia possibile connettersi a un database di Microsoft SQL Server usando il provider OleDb, il provider SqlClient è molto più efficiente perché è stato progettato e ottimizzato in modo specifico per SQL Server.

Quando si accede ai dati a livello di codice, viene comunemente usato il modello seguente:

  • Stabilire una connessione al database.
  • Eseguire un comando.
  • Per SELECT le query, usare i record risultanti.

Esistono classi ADO.NET separate per l'esecuzione di ognuno di questi passaggi. Per connettersi a un database usando il provider SqlClient, ad esempio, usare la SqlConnection classe . Per eseguire un INSERTcomando , UPDATE, DELETEo SELECT al database, usare la SqlCommand classe .

Ad eccezione del wrapping delle modifiche al database all'interno di un'esercitazione sulle transazioni , non è stato necessario scrivere codice di basso livello ADO.NET perché il codice generato automaticamente da TableAdapter include le funzionalità necessarie per connettersi al database, eseguire comandi, recuperare dati e popolare tali dati in DataTable. Tuttavia, potrebbero esserci momenti in cui è necessario personalizzare queste impostazioni di basso livello. Nei passaggi successivi si esaminerà come accedere agli oggetti ADO.NET usati internamente dagli oggetti TableAdapter.

Passaggio 1: Esame della proprietà di connessione

Ogni classe TableAdapter ha una Connection proprietà che specifica le informazioni di connessione al database. Il tipo di dati e ConnectionString il valore di questa proprietà sono determinati dalle selezioni effettuate nella Configurazione guidata TableAdapter. Tenere presente che quando si aggiunge un oggetto TableAdapter a un dataset tipizzato, questa procedura guidata richiede l'origine del database (vedere la figura 1). Nell'elenco a discesa di questo primo passaggio sono inclusi i database specificati nel file di configurazione e tutti gli altri database nel Connections dati di Esplora server. Se il database da usare non esiste nell'elenco a discesa, è possibile specificare una nuova connessione al database facendo clic sul pulsante Nuova connessione e specificando le informazioni di connessione necessarie.

Primo passaggio della Configurazione guidata TableAdapter

Figura 1: Primo passaggio della Configurazione guidata TableAdapter (fare clic per visualizzare l'immagine a dimensione intera)

Esaminare il codice per la proprietà TableAdapter s Connection . Come indicato nell'esercitazione Creazione di un livello di accesso ai dati , è possibile visualizzare il codice TableAdapter generato automaticamente passando alla finestra Visualizzazione classi, eseguendo il drill-down alla classe appropriata e quindi facendo doppio clic sul nome del membro.

Passare alla finestra Visualizzazione classi passando al menu Visualizza e scegliendo Visualizzazione classi (o digitando CTRL+MAIUSC+C). Nella parte superiore della finestra Visualizzazione classi eseguire il drill-down nello NorthwindTableAdapters spazio dei nomi e selezionare la ProductsTableAdapter classe . Verranno visualizzati i ProductsTableAdapter membri nella metà inferiore della visualizzazione classi, come illustrato nella figura 2. Fare doppio clic sulla proprietà per visualizzarne il Connection codice.

Fare doppio clic sulla proprietà Connection nella visualizzazione Classi per visualizzare il codice generato automaticamente

Figura 2: Double-Click la proprietà Connection nella visualizzazione Classi per visualizzare il codice generato automaticamente

La proprietà tableAdapter Connection e altro codice correlato alla connessione sono i seguenti:

private System.Data.SqlClient.SqlConnection _connection;
private void InitConnection() {
    this._connection = new System.Data.SqlClient.SqlConnection();
    this._connection.ConnectionString = 
        ConfigurationManager.ConnectionStrings["NORTHWNDConnectionString"].ConnectionString;
}
internal System.Data.SqlClient.SqlConnection Connection {
    get {
        if ((this._connection == null)) {
            this.InitConnection();
        }
        return this._connection;
    }
    set {
        this._connection = value;
        if ((this.Adapter.InsertCommand != null)) {
            this.Adapter.InsertCommand.Connection = value;
        }
        if ((this.Adapter.DeleteCommand != null)) {
            this.Adapter.DeleteCommand.Connection = value;
        }
        if ((this.Adapter.UpdateCommand != null)) {
            this.Adapter.UpdateCommand.Connection = value;
        }
        for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
            if ((this.CommandCollection[i] != null)) {
                ((System.Data.SqlClient.SqlCommand)
                    (this.CommandCollection[i])).Connection = value;
            }
        }
    }
}

Quando viene creata un'istanza della classe TableAdapter, la variabile _connection membro è uguale a null. Quando si accede alla Connection proprietà, verifica innanzitutto se è stata creata un'istanza della _connection variabile membro. In caso contrario, viene richiamato il InitConnection metodo , che crea _connection un'istanza e ne imposta ConnectionString la proprietà sul valore stringa di connessione specificato dal primo passaggio della Configurazione guidata TableAdapter.

La Connection proprietà può anche essere assegnata a un SqlConnection oggetto . In questo modo, il nuovo SqlConnection oggetto viene associato a ognuno degli oggetti TableAdapter SqlCommand .

Passaggio 2: Esposizione delle impostazioni di Connection-Level

Le informazioni di connessione devono rimanere incapsulate all'interno di TableAdapter e non essere accessibili ad altri livelli nell'architettura dell'applicazione. Possono tuttavia verificarsi scenari in cui le informazioni a livello di connessione di TableAdapter devono essere accessibili o personalizzabili per una query, un utente o una pagina ASP.NET.

È possibile estendere ProductsTableAdapter in Northwind DataSet per includere una ConnectionString proprietà che può essere usata dal livello della logica di business per leggere o modificare la stringa di connessione usata dall'oggetto TableAdapter.

Nota

Un stringa di connessione è una stringa che specifica le informazioni di connessione al database, ad esempio il provider da usare, il percorso del database, le credenziali di autenticazione e altre impostazioni correlate al database. Per un elenco di modelli di stringa di connessione usati da un'ampia gamma di archivi dati e provider, vedere ConnectionStrings.com.

Come illustrato nell'esercitazione Creazione di un livello di accesso ai dati , è possibile estendere le classi generate automaticamente di DataSet tipizzato tramite l'uso di classi parziali. Creare prima di tutto una nuova sottocartella nel progetto denominato ConnectionAndCommandSettings sotto la ~/App_Code/DAL cartella .

Aggiungere una sottocartella denominata ConnectionAndCommandSettings

Figura 3: Aggiungere una sottocartella denominata ConnectionAndCommandSettings

Aggiungere un nuovo file di classe denominato ProductsTableAdapter.ConnectionAndCommandSettings.cs e immettere il codice seguente:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace NorthwindTableAdapters
{
    public partial class ProductsTableAdapter
    {
        public string ConnectionString
        {
            get
            {
                return this.Connection.ConnectionString;
            }
            set
            {
                this.Connection.ConnectionString = value;
            }
        }
    }
}

Questa classe parziale aggiunge una public proprietà denominata ConnectionString alla ProductsTableAdapter classe che consente a qualsiasi livello di leggere o aggiornare il stringa di connessione per la connessione sottostante di TableAdapter.

Con questa classe parziale creata (e salvata), aprire la ProductsBLL classe . Passare a uno dei metodi esistenti e digitare Adapter e quindi premere il tasto punto per visualizzare IntelliSense. Verrà visualizzata la nuova ConnectionString proprietà disponibile in IntelliSense, vale a dire che è possibile leggere o modificare questo valore a livello di codice dal BLL.

Esposizione dell'intero oggetto connection

Questa classe parziale espone una sola proprietà dell'oggetto connessione sottostante: ConnectionString. Se si desidera rendere disponibile l'intero oggetto connessione oltre i limiti del TableAdapter, in alternativa è possibile modificare il Connection livello di protezione della proprietà. Il codice generato automaticamente esaminato nel passaggio 1 ha mostrato che la proprietà TableAdapter è Connection contrassegnata come internal, vale a dire che è possibile accedervi solo dalle classi nello stesso assembly. Questa modifica può tuttavia essere modificata tramite la proprietà TableAdapter.ConnectionModifier

Aprire il Northwind set di dati, fare clic su ProductsTableAdapter nella Designer e passare alla Finestra Proprietà. Verrà visualizzato il set sul ConnectionModifier relativo valore predefinito, Assembly. Per rendere disponibile la Connection proprietà all'esterno dell'assembly DataSet tipizzato, modificare la ConnectionModifier proprietà in Public.

Il livello di accessibilità della proprietà connection può essere configurato tramite la proprietà ConnectionModifier

Figura 4: Il Connection livello di accessibilità della proprietà può essere configurato tramite la ConnectionModifier proprietà (fare clic per visualizzare l'immagine a dimensione intera)

Salvare l'oggetto DataSet e quindi tornare alla ProductsBLL classe . Come in precedenza, passare a uno dei metodi esistenti e digitare Adapter e quindi premere la chiave punto per visualizzare IntelliSense. L'elenco deve includere una Connection proprietà, ovvero è ora possibile leggere o assegnare a livello di codice le impostazioni a livello di connessione dal BLL.

Un oggetto TableAdapter è costituito da una query principale che, per impostazione predefinita, ha istruzioni , UPDATEe DELETE generate INSERTautomaticamente. Le istruzioni , UPDATEe DELETE della query INSERTprincipale vengono implementate nel codice tableAdapter come oggetto adattatore dati ADO.NET tramite la Adapter proprietà . Analogamente alla relativa Connection proprietà, il Adapter tipo di dati della proprietà viene determinato dal provider di dati usato. Poiché queste esercitazioni usano il provider SqlClient, la Adapter proprietà è di tipo SqlDataAdapter.

La proprietà TableAdapter ha Adapter tre proprietà di tipo SqlCommand usate per rilasciare le INSERTistruzioni , UPDATEe DELETE :

  • InsertCommand
  • UpdateCommand
  • DeleteCommand

Un SqlCommand oggetto è responsabile dell'invio di una query specifica al database e dispone di proprietà come : CommandText, che contiene l'istruzione SQL ad hoc o la stored procedure da eseguire; e Parameters, che è una raccolta di SqlParameter oggetti . Come illustrato nell'esercitazione Creazione di un livello di accesso ai dati, questi oggetti comando possono essere personalizzati tramite il Finestra Proprietà.

Oltre alla query principale, TableAdapter può includere un numero variabile di metodi che, quando richiamati, inviano un comando specificato al database. L'oggetto comando della query principale e gli oggetti comando per tutti i metodi aggiuntivi vengono archiviati nella proprietà TableAdapter.CommandCollection

Esaminare il codice generato da ProductsTableAdapter in Northwind DataSet per queste due proprietà e i relativi metodi helper e variabili membro di supporto:

private System.Data.SqlClient.SqlDataAdapter _adapter;
private void InitAdapter() {
    this._adapter = new System.Data.SqlClient.SqlDataAdapter();
    
    ... Code that creates the InsertCommand, UpdateCommand, ...
    ... and DeleteCommand instances - omitted for brevity ...
}
private System.Data.SqlClient.SqlDataAdapter Adapter {
    get {
        if ((this._adapter == null)) {
            this.InitAdapter();
        }
        return this._adapter;
    }
}
private System.Data.SqlClient.SqlCommand[] _commandCollection;
private void InitCommandCollection() {
    this._commandCollection = new System.Data.SqlClient.SqlCommand[9];
    ... Code that creates the command objects for the main query and the ...
    ... ProductsTableAdapter�s other eight methods - omitted for brevity ...
}
protected System.Data.SqlClient.SqlCommand[] CommandCollection {
    get {
        if ((this._commandCollection == null)) {
            this.InitCommandCollection();
        }
        return this._commandCollection;
    }
}

Il codice per le Adapter proprietà e CommandCollection simula attentamente quello della Connection proprietà . Esistono variabili membro che contengono gli oggetti utilizzati dalle proprietà. Le funzioni di accesso delle proprietà get iniziano controllando se la variabile membro corrispondente è null. In tal caso, viene chiamato un metodo di inizializzazione che crea un'istanza della variabile membro e assegna le proprietà principali correlate ai comandi.

Passaggio 4: Esposizione delle impostazioni di Command-Level

Idealmente, le informazioni a livello di comando devono rimanere incapsulate all'interno del livello di accesso ai dati. Se queste informazioni devono essere necessarie in altri livelli dell'architettura, tuttavia, possono essere esposte tramite una classe parziale, proprio come con le impostazioni a livello di connessione.

Poiché TableAdapter ha solo una singola Connection proprietà, il codice per esporre le impostazioni a livello di connessione è abbastanza semplice. Le cose sono un po'più complicate quando si modificano le impostazioni a livello di comando perché TableAdapter può avere più oggetti comando - un InsertCommandoggetto , UpdateCommande , DeleteCommandinsieme a un numero variabile di oggetti comando nella CommandCollection proprietà. Quando si aggiornano le impostazioni a livello di comando, queste impostazioni devono essere propagate a tutti gli oggetti comando.

Si supponga, ad esempio, che in TableAdapter siano state eseguite alcune query che hanno impiegato molto tempo per l'esecuzione. Quando si usa TableAdapter per eseguire una di queste query, è possibile aumentare la proprietà dell'oggetto CommandTimeoutcomando. Questa proprietà specifica il numero di secondi per attendere l'esecuzione del comando e il valore predefinito è 30.

Per consentire la regolazione della CommandTimeout proprietà da parte del BLL, aggiungere il metodo seguente public all'uso ProductsDataTable del file di classe parziale creato nel passaggio 2 (ProductsTableAdapter.ConnectionAndCommandSettings.cs):

public void SetCommandTimeout(int timeout)
{
    if (this.Adapter.InsertCommand != null)
        this.Adapter.InsertCommand.CommandTimeout = timeout;
    if (this.Adapter.DeleteCommand != null)
        this.Adapter.DeleteCommand.CommandTimeout = timeout;
    if (this.Adapter.UpdateCommand != null)
        this.Adapter.UpdateCommand.CommandTimeout = timeout;
    for (int i = 0; i < this.CommandCollection.Length; i++)
        if (this.CommandCollection[i] != null)
            this.CommandCollection[i].CommandTimeout = timeout;
}

Questo metodo può essere richiamato dal livello BLL o Presentation per impostare il timeout dei comandi per tutti i problemi dei comandi da tale istanza di TableAdapter.

Nota

Le Adapter proprietà e CommandCollection sono contrassegnate come private, ovvero possono essere accessibili solo dal codice all'interno di TableAdapter. A differenza della Connection proprietà, questi modificatori di accesso non sono configurabili. Pertanto, se è necessario esporre le proprietà a livello di comando ad altri livelli nell'architettura, è necessario usare l'approccio di classe parziale descritto in precedenza per fornire un metodo o una public proprietà che legge o scrive negli private oggetti comando.

Riepilogo

I TableAdapter all'interno di un dataset tipizzato servono per incapsulare i dettagli di accesso ai dati e la complessità. L'uso di TableAdapters non deve preoccuparsi di scrivere codice ADO.NET per connettersi al database, emettere un comando o popolare i risultati in una tabella dati. È tutto gestito automaticamente per noi.

Tuttavia, potrebbero verificarsi momenti in cui è necessario personalizzare le specifiche di ADO.NET di basso livello, ad esempio la modifica del stringa di connessione o i valori di timeout predefinito della connessione o del comando. TableAdapter ha proprietà generate Connectionautomaticamente , Adaptere , CommandCollection ma queste sono internal o private, per impostazione predefinita. Queste informazioni interne possono essere esposte estendendo TableAdapter usando classi parziali per includere public metodi o proprietà. In alternativa, il modificatore di Connection accesso alla proprietà TableAdapter può essere configurato tramite la proprietà TableAdapter.ConnectionModifier

Programmazione felice!

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Microsoft Web dal 1998. Scott lavora come consulente indipendente, allenatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2,0 in 24 Ore. Può essere raggiunto a mitchell@4GuysFromRolla.com. o tramite il suo blog, che può essere trovato in http://ScottOnWriting.NET.

Grazie speciali

Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali per questa esercitazione sono stati Burnadette Leigh, S ren Jacob Lauritsen, Teresa Murphy e Hilton Geisenow. Interessati a esaminare i prossimi articoli MSDN? In tal caso, lasciami una riga in mitchell@4GuysFromRolla.com.