Delen via


De verbinding- en Command-Level-instellingen van de Data Access-laag configureren (C#)

door Scott Mitchell

PDF downloaden

De TableAdapters in een getypte gegevensset zorgen automatisch voor het maken van verbinding met de database, het uitgeven van opdrachten en het invullen van een DataTable met de resultaten. Er zijn echter situaties waarin we deze details zelf willen uitvoeren. In deze zelfstudie leert u echter hoe u toegang krijgt tot de instellingen op databaseverbindings- en opdrachtniveau in de TableAdapter.

Introductie

In de reeks zelfstudies hebben we Getypte gegevenssets gebruikt om de Data Access-laag en zakelijke objecten van onze gelaagde architectuur te implementeren. Zoals besproken in de eerste handleiding, fungeren de Gegevenstabellen van Getypte Gegevenssets als opslagplaatsen van gegevens, terwijl de TableAdapters dienen als wrappers om te communiceren met de database voor het ophalen en wijzigen van de onderliggende gegevens. De TableAdapters encapsuleren de complexiteit van het werken met de database en bespaart ons zodat we geen code hoeven te schrijven om verbinding te maken met de database, een opdracht uit te voeren of de resultaten in een DataTable te plaatsen.

Er zijn echter momenten waarop we in de diepten van de TableAdapter moeten graven en code moeten schrijven die rechtstreeks met de ADO.NET objecten werkt. In de tutorial Aanpassen van databasewijzigingen binnen een transactie hebben we bijvoorbeeld methoden toegevoegd aan de "TableAdapter" voor het starten, committeren en terugdraaien van ADO.NET-transacties. Deze methoden gebruikten een intern, handmatig gemaakt SqlTransaction object dat is toegewezen aan de TableAdapter-objecten SqlCommand .

In deze zelfstudie bekijken we hoe u toegang krijgt tot de instellingen voor de databaseverbinding en opdrachtniveau in de TableAdapter. In het bijzonder voegen we functionaliteit toe aan de ProductsTableAdapter waarmee toegang tot de onderliggende verbindingsreeks en de time-outinstellingen voor opdrachten mogelijk wordt.

Werken met gegevens met behulp van ADO.NET

Microsoft .NET Framework bevat een overvloed aan klassen die speciaal zijn ontworpen om met gegevens te werken. Deze klassen, gevonden in de System.Data naamruimte, worden de ADO.NET klassen genoemd. Sommige klassen onder de paraplu ADO.NET zijn gekoppeld aan een bepaalde gegevensprovider. U kunt een gegevensprovider beschouwen als een communicatiekanaal waarmee informatie tussen de ADO.NET klassen en het onderliggende gegevensarchief kan stromen. Er zijn gegeneraliseerde providers, zoals OleDb en ODBC, evenals providers die speciaal zijn ontworpen voor een bepaald databasesysteem. Hoewel het bijvoorbeeld mogelijk is om verbinding te maken met een Microsoft SQL Server-database met behulp van de OleDb-provider, is de SqlClient-provider veel efficiënter omdat deze speciaal is ontworpen en geoptimaliseerd voor SQL Server.

Bij programmatisch toegang tot gegevens wordt het volgende patroon vaak gebruikt:

  • Maak een verbinding met de database.
  • Geef een opdracht.
  • Werk met de resulterende records voor SELECT queries.

Er zijn afzonderlijke ADO.NET klassen voor het uitvoeren van elk van deze stappen. Als u verbinding wilt maken met een database met behulp van de SqlClient-provider, gebruikt u bijvoorbeeld de SqlConnection klasse. Als u een INSERT, UPDATEDELETEof SELECT opdracht aan de database wilt uitgeven, gebruikt u de SqlCommand klasse.

Behalve de tutorial Databasewijzigingen binnen een transactie wrappen, hebben we geen ADO.NET-code op laag niveau hoeven schrijven omdat de automatisch gegenereerde code van TableAdapters de functionaliteit bevat die nodig is om verbinding te maken met de database, opdrachten uit te voeren, gegevens op te halen en die gegevens in DataTables te vullen. Het kan echter voorkomen dat we deze instellingen op laag niveau moeten aanpassen. In de volgende stappen bekijken we hoe we de ADO.NET objecten die intern door de TableAdapters worden gebruikt, kunt gebruiken.

Stap 1: Onderzoeken met de eigenschap Verbinding

Elke TableAdapter-klasse heeft een Connection eigenschap waarmee de verbindingsgegevens van de database worden opgegeven. Het gegevenstype en de ConnectionString-waarde van deze eigenschap worden bepaald door de selecties die zijn gemaakt in de TableAdapter-configuratiewizard. Zoals u zich herinnert, vraagt deze wizard ons om de databasebron (zie afbeelding 1) wanneer we voor het eerst een TableAdapter toevoegen aan een getypte gegevensset. De vervolgkeuzelijst in deze eerste stap bevat de databases die zijn opgegeven in het configuratiebestand, evenals andere databases in de gegevensverbindingen van Server Explorer. Als de database die we willen gebruiken niet bestaat in de vervolgkeuzelijst, kan een nieuwe databaseverbinding worden opgegeven door op de knop Nieuwe verbinding te klikken en de benodigde verbindingsgegevens op te geven.

De eerste stap van de TableAdapter Configuratie Wizard

Afbeelding 1: De eerste stap van de wizard TableAdapter-configuratie (klik om de volledige afbeelding weer te geven)

Laten we de code van de eigenschap van de TableAdapter even inspecteren Connection. Zoals vermeld in de zelfstudie Een Gegevenstoegangslaag maken , kunnen we de automatisch gegenereerde TableAdapter-code bekijken door naar het venster Class View te gaan, in te zoomen op de juiste klasse en vervolgens te dubbelklikken op de naam van het lid.

Navigeer naar het venster Klasweergave door naar het menu Beeld te gaan en Klasseweergave te kiezen (of door Ctrl+Shift+C te typen). In de bovenste helft van het venster Class View kunt u inzoomen op de NorthwindTableAdapters naamruimte en de ProductsTableAdapter klasse selecteren. Hiermee worden de ProductsTableAdapter leden weergegeven in de onderste helft van de klasseweergave, zoals weergegeven in afbeelding 2. Dubbelklik op de Connection eigenschap om de code weer te geven.

Double-Click de verbindingseigenschap in de klasseweergave om de automatisch gegenereerde code weer te geven

Afbeelding 2: Double-Click de verbindingseigenschap in de klasseweergave om de automatisch gegenereerde code weer te geven

De eigenschap TableAdapter Connection en andere verbindingsgerelateerde code volgt:

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;
            }
        }
    }
}

Wanneer de TableAdapter-klasse wordt geïnstantieerd, is de lidvariabele _connection gelijk aan null. Wanneer de Connection eigenschap wordt geopend, wordt eerst gecontroleerd of de _connection lidvariabele is geïnstantieerd. Als dat niet het geval is, wordt de methode InitConnection aangeroepen, die _connection aanmaakt en de eigenschap ConnectionString instelt op de verbindingsreekswaarde die is opgegeven in de eerste stap van de TableAdapter-configuratiewizard.

De Connection eigenschap kan ook worden toegewezen aan een SqlConnection object. Hiermee koppelt u het nieuwe SqlConnection object aan elk van de TableAdapter-objecten SqlCommand .

Stap 2: Connection-Level-instellingen beschikbaar maken

De verbindingsgegevens moeten worden ingekapseld in de TableAdapter en zijn niet toegankelijk voor andere lagen in de toepassingsarchitectuur. Er kunnen echter scenario's zijn waarin de informatie op verbindingsniveau van TableAdapter toegankelijk of aanpasbaar moet zijn voor een query, gebruiker of ASP.NET pagina.

Laten we de ProductsTableAdapter gegevensset Northwind uitbreiden om een ConnectionString eigenschap op te nemen die door de bedrijfslogicalaag kan worden gebruikt om de verbindingsreeks te lezen of te wijzigen die door de TableAdapter wordt gebruikt.

Opmerking

Een verbindingsreeks is een tekenreeks die databaseverbindingsgegevens opgeeft, zoals de provider die moet worden gebruikt, de locatie van de database, verificatiereferenties en andere database-gerelateerde instellingen. Zie ConnectionStrings.com voor een lijst met verbindingsreekspatronen die worden gebruikt door verschillende gegevensarchieven en providers.

Zoals besproken in de zelfstudie Een Gegevenstoegangslaag maken , kunnen de automatisch gegenereerde klassen van de Getypte Gegevensset worden uitgebreid door het gebruik van gedeeltelijke klassen. Maak eerst een nieuwe submap in het project met de naam ConnectionAndCommandSettings onder de ~/App_Code/DAL map.

Een submap met de naam ConnectionAndCommandSettings toevoegen

Afbeelding 3: Een submap met de naam toevoegen ConnectionAndCommandSettings

Voeg een nieuw klassebestand toe met de naam ProductsTableAdapter.ConnectionAndCommandSettings.cs en voer de volgende code in:

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;
            }
        }
    }
}

Deze gedeeltelijke klasse voegt een public eigenschap met de naam ConnectionString toe aan de ProductsTableAdapter klasse waarmee elke laag de verbindingsreeks voor de onderliggende verbinding van TableAdapter kan lezen of bijwerken.

Als deze gedeeltelijke klasse is gemaakt (en opgeslagen), opent u de ProductsBLL klasse. Ga naar een van de bestaande methoden en typ Adapter en druk op de punttoets om IntelliSense weer te geven. U ziet nu de nieuwe ConnectionString eigenschap die beschikbaar is in IntelliSense, wat betekent dat u deze waarde programmatisch kunt lezen of aanpassen vanuit de BLL.

Het hele verbindingsobject beschikbaar maken

Deze gedeeltelijke klasse bevat slechts één eigenschap van het onderliggende verbindingsobject: ConnectionString. Als u het hele verbindingsobject beschikbaar wilt maken buiten de grenzen van de TableAdapter, kunt u ook het beveiligingsniveau van de Connection eigenschap wijzigen. De automatisch gegenereerde code die we in stap 1 hebben onderzocht, heeft aangetoond dat de eigenschap TableAdapter Connection is gemarkeerd als internal, wat betekent dat deze alleen toegankelijk is voor klassen in dezelfde assembly. Dit kan echter worden gewijzigd via de eigenschap TableAdapter ConnectionModifier .

Open de Northwind DataSet, klik op de ProductsTableAdapter ontwerpfunctie en navigeer naar het venster Eigenschappen. Daar ziet u dat de waarde is ingesteld op de ConnectionModifier standaardwaarde. Assembly Als u de Connection eigenschap beschikbaar wilt maken buiten de getypeerde dataset-assembly, wijzigt u de ConnectionModifier eigenschap in Public.

Het toegankelijkheidsniveau van de verbindingseigenschap kan worden geconfigureerd via de eigenschap ConnectionModifier

Afbeelding 4: Het Connection toegankelijkheidsniveau van de eigenschap kan worden geconfigureerd via de ConnectionModifier eigenschap (klik om de afbeelding op volledige grootte weer te geven)

Sla de DataSet op en ga vervolgens terug naar de ProductsBLL klasse. Net als voorheen gaat u naar een van de bestaande methoden, typt u Adapter, en drukt vervolgens op de punttoets om IntelliSense weer te geven. De lijst moet een Connection eigenschap bevatten, wat betekent dat u nu programmatisch instellingen op verbindingsniveau van de BLL kunt lezen of toewijzen.

Een TableAdapter bestaat uit een hoofdquery die standaard automatisch gegenereerde INSERT, UPDATEen DELETE instructies heeft. Deze hoofdquery’s INSERT, UPDATE, en DELETE-instructies worden in de code van TableAdapters geïmplementeerd als een ADO.NET-gegevensadapterobject via de Adapter-eigenschap. Net als bij Connection de eigenschap wordt het gegevenstype van de Adapter eigenschap bepaald door de gegevensprovider die wordt gebruikt. Omdat deze zelfstudies de SqlClient-provider gebruiken, is de eigenschap van het Adapter type SqlDataAdapter.

De eigenschap s Adapter van TableAdapter heeft drie eigenschappen van het type SqlCommand waarmee de INSERT, UPDATE en DELETE instructies worden uitgegeven.

  • InsertCommand
  • UpdateCommand
  • DeleteCommand

Een SqlCommand-object is verantwoordelijk voor het verzenden van een bepaalde query naar de database en heeft eigenschappen zoals: CommandText, die de ad-hoc SQL-instructie of opgeslagen procedure bevat die moet worden uitgevoerd; en Parameters, een verzameling van SqlParameter-objecten. Zoals we hebben gezien in de zelfstudie Een Gegevenstoegangslaag maken , kunnen deze opdrachtobjecten worden aangepast via het venster Eigenschappen.

Naast de hoofdquery kan de TableAdapter een variabel aantal methoden bevatten die, wanneer deze worden aangeroepen, een opgegeven opdracht naar de database verzenden. Het opdrachtobject van de hoofdquery en de opdrachtobjecten voor alle aanvullende methoden worden opgeslagen in de eigenschap TableAdapter CommandCollection .

Laten we even de code bekijken die is gegenereerd door de ProductsTableAdapter in de Northwind DataSet voor deze twee eigenschappen en hun ondersteunende lidvariabelen en helpermethoden.

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;
    }
}

De code voor de Adapter en CommandCollection eigenschappen bootst die van de Connection eigenschap nauw na. Er zijn lidvariabelen die de objecten bevatten die door de eigenschappen worden gebruikt. De eigenschapstoegangsmethoden get begint met te controleren of de bijbehorende lidvariabele null is. Als dit het geval is, wordt een initialisatiemethode aangeroepen waarmee een exemplaar van de lidvariabele wordt gemaakt en de belangrijkste eigenschappen van de opdracht worden toegewezen.

Stap 4: Command-Level-instellingen beschikbaar maken

In het ideale geval moet de informatie op opdrachtniveau ingekapseld blijven binnen de Gegevenstoegangslaag. Als deze informatie nodig is in andere lagen van de architectuur, kan deze echter worden weergegeven via een gedeeltelijke klasse, net als bij de instellingen op verbindingsniveau.

Omdat TableAdapter slechts één Connection eigenschap heeft, is de code voor het weergeven van instellingen op verbindingsniveau vrij eenvoudig. Dingen zijn iets ingewikkelder bij het wijzigen van instellingen op opdrachtniveau, omdat de TableAdapter meerdere opdrachtobjecten kan hebben: een InsertCommand, UpdateCommanden, samen DeleteCommandmet een variabel aantal opdrachtobjecten in de CommandCollection eigenschap. Wanneer u instellingen op opdrachtniveau bijwerkt, moeten deze instellingen worden doorgegeven aan alle opdrachtobjecten.

Stel dat er bepaalde query's in de TableAdapter zijn die een buitengewone lange tijd hebben geduurd om uit te voeren. Wanneer u de TableAdapter gebruikt om een van deze query's uit te voeren, is het misschien handig om de eigenschap van CommandTimeouthet opdrachtobject te verhogen. Met deze eigenschap geeft u het aantal seconden op dat moet worden gewacht totdat de opdracht wordt uitgevoerd en de standaardwaarde is ingesteld op 30.

Als u wilt toestaan dat de CommandTimeout eigenschap wordt aangepast door de BLL, voegt u de volgende public methode toe aan het ProductsDataTable gebruik van het gedeeltelijke klassebestand dat is gemaakt in stap 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;
}

Deze methode kan worden aangeroepen vanuit de BLL of Presentatielaag om de time-out van de opdracht in te stellen voor alle opdrachten die door dat TableAdapter-exemplaar worden uitgevoerd.

Opmerking

De Adapter eigenschappen CommandCollection worden gemarkeerd als private, wat betekent dat ze alleen kunnen worden geopend vanuit code binnen de TableAdapter. In tegenstelling tot de Connection eigenschap kunnen deze toegangsaanpassingen niet worden geconfigureerd. Als u daarom eigenschappen op opdrachtniveau beschikbaar wilt maken voor andere lagen in de architectuur, moet u de hierboven besproken gedeeltelijke klassebenadering gebruiken om een public methode of eigenschap op te geven die naar de private opdrachtobjecten leest of schrijft.

Samenvatting

De TableAdapters in een getypte gegevensset dienen om details en complexiteit van gegevenstoegang in te kapselen. Met TableAdapters hoeft u zich geen zorgen te maken over het schrijven van ADO.NET code om verbinding te maken met de database, een opdracht uit te geven of de resultaten in een gegevenstabel te vullen. Het wordt allemaal automatisch voor ons afgehandeld.

Het kan echter voorkomen dat we de specifieke aspecten van ADO.NET op laag niveau moeten aanpassen, zoals het wijzigen van de connection string of de standaard verbinding of time-outwaarden voor verbindingen of opdrachten. De TableAdapter heeft automatisch gegenereerde Connection, Adapter en CommandCollection eigenschappen, maar deze zijn standaard internal of private. Deze interne informatie kan worden weergegeven door de TableAdapter uit te breiden met behulp van gedeeltelijke klassen om methoden of eigenschappen op te nemen public . U kunt ook de eigenschapstoegangsaanpassing van TableAdapter Connection configureren via de eigenschap TableAdapter ConnectionModifier .

Veel plezier met programmeren!

Over de auteur

Scott Mitchell, auteur van zeven ASP/ASP.NET-boeken en oprichter van 4GuysFromRolla.com, werkt sinds 1998 met Microsoft-webtechnologieën. Scott werkt als onafhankelijk consultant, trainer en schrijver. Zijn laatste boek is Sams Teach Yourself ASP.NET 2.0 in 24 uur. Hij kan worden bereikt op mitchell@4GuysFromRolla.com.

Speciale dank aan

Deze tutorialreeks is beoordeeld door veel behulpzame beoordelers. Hoofdrevisoren voor deze zelfstudie waren Burnadette Leigh, S ren Jacob Lauritsen, Teresa Murphy en Hilton Geisenow. Bent u geïnteresseerd in het bekijken van mijn aanstaande MSDN-artikelen? Zo ja, laat iets van je horen via mitchell@4GuysFromRolla.com.