Dela via


Spara data i databasen i .NET Framework-program

Anmärkning

Klassen DataSet och relaterade klasser är äldre .NET Framework-tekniker från början av 2000-talet som gör det möjligt för program att arbeta med data i minnet medan apparna kopplas från databasen. Teknikerna är särskilt användbara för appar som gör det möjligt för användare att ändra data och spara ändringarna tillbaka till databasen. Även om datauppsättningar är en bevisad framgångsrik teknik är den rekommenderade metoden för nya .NET-program att använda Entity Framework Core. Entity Framework är ett mer naturligt sätt att arbeta med tabelldata som objektmodeller och har ett enklare programmeringsgränssnitt.

Datamängden är en minnesintern kopia av data. Om du ändrar dessa data är det bra att spara ändringarna i databasen igen. Du gör detta på något av tre sätt:

  • Genom att anropa en av Update-metoderna i en TableAdapter

  • Genom att anropa en av DBDirect metoderna i TableAdapter

  • Genom att anropa UpdateAll metoden på TableAdapterManager som Visual Studio genererar åt dig när datauppsättningen innehåller tabeller som är relaterade till andra tabeller i datauppsättningen

När du binder datauppsättningstabeller till kontroller på en Windows-formulär- eller XAML-sida utför databindningsarkitekturen allt arbete åt dig.

Om du är bekant med TableAdapters kan du gå direkt till något av följande avsnitt:

Ämne Beskrivning
Infoga nya poster i en databas Så här utför du uppdateringar och infogningar med TableAdapters eller kommandoobjekt
Uppdatera data med hjälp av en TableAdapter Så här utför du uppdateringar med TableAdapters
hierarkisk uppdatering Så här utför du uppdateringar från en datauppsättning med två eller flera relaterade tabeller
Hantera ett samtidighetsfel Hantera undantag när två användare försöker ändra samma data i en databas samtidigt
Gör så här: Spara data med hjälp av en transaktion Så här sparar du data i en transaktion med hjälp av systemet. Namnområde för transaktioner och ett TransactionScope-objekt
Spara data i en transaktion Genomgång för att skapa en Windows Forms-applikation för att demonstrera hur man sparar data i en databas inom en transaktion
Spara data i en databas (flera tabeller) Så här redigerar du poster och sparar ändringar i flera tabeller i databasen igen
Spara data från ett objekt till en databas Så här skickar du data från ett objekt som inte finns i en datauppsättning till en databas med hjälp av en TableAdapter DbDirect-metod
Spara data med TableAdapter DBDirect-metoderna Så här använder du TableAdapter för att skicka SQL-frågor direkt till databasen
Spara en datamängd som XML Spara en datamängd i ett XML-dokument

Uppdateringar i två steg

Att uppdatera en datakälla är en tvåstegsprocess. Det första steget är att uppdatera datauppsättningen med nya poster, ändrade poster eller borttagna poster. Om ditt program aldrig skickar tillbaka ändringarna till datakällan är du klar med uppdateringen.

Om du skickar tillbaka ändringarna till databasen krävs ett andra steg. Om du inte använder databundna kontroller måste du manuellt anropa metoden Update för samma TableAdapter (eller dataadapter) som du använde för att fylla i datasetet. Du kan dock också använda olika adaptrar, till exempel för att flytta data från en datakälla till en annan eller för att uppdatera flera datakällor. Om du inte använder databindning och sparar ändringar för relaterade tabeller måste du manuellt instansiera en variabel för den automatiskt genererade TableAdapterManager klassen och sedan anropa dess UpdateAll metod.

Konceptuellt diagram över uppdateringar av datamängd

En datauppsättning innehåller samlingar med tabeller som innehåller en samling rader. Om du tänker uppdatera en underliggande datakälla senare måste du använda metoderna på DataTable.DataRowCollection egenskapen när du lägger till eller tar bort rader. Dessa metoder utför den ändringsspårning som behövs för att uppdatera datakällan. Om du anropar RemoveAt-samlingen på Rader-egenskapen, kommer borttagningen inte att kommuniceras tillbaka till databasen.

Sammanfoga datauppsättningar

Du kan uppdatera innehållet i en datauppsättning genom att slå samman den med en annan datauppsättning. Detta innebär att du kopierar innehållet i en källdatauppsättning till den anropande datamängden (kallas för måldatauppsättningen ). När du sammanfogar datauppsättningar läggs nya poster i källdatauppsättningen till i måldatauppsättningen. Dessutom läggs extra kolumner i källdatauppsättningen till i måldatauppsättningen. Att slå samman datauppsättningar är användbart när du har en lokal datauppsättning och du får en andra datauppsättning från ett annat program. Det är också användbart när du får en andra datamängd från en komponent, till exempel en XML-webbtjänst, eller när du behöver integrera data från flera datauppsättningar.

När du sammanfogar datauppsättningar kan du skicka ett booleskt argument (preserveChanges) som talar om Merge för metoden om du vill behålla befintliga ändringar i måldatauppsättningen. Eftersom datauppsättningar har flera versioner av poster är det viktigt att komma ihåg att fler än en version av posterna sammanfogas. Följande tabell visar hur en post i två datauppsättningar sammanfogas:

DataRowVersion Måldatasätt Källdatauppsättning
Original James Wilson James C. Wilson
Ström Jim Wilson James C. Wilson

Anropa Merge-metoden på den föregående tabellen med preserveChanges=false targetDataset.Merge(sourceDataset) resulterar i följande data:

DataRowVersion Måldatauppsättning Källdatauppsättning
Original James C. Wilson James C. Wilson
Ström James C. Wilson James C. Wilson

Att anropa metoden med preserveChanges = true targetDataset.Merge(sourceDataset, true) resulterar i följande data:

DataRowVersion Måldatauppsättning Källdatauppsättning
Original James C. Wilson James C. Wilson
Ström Jim Wilson James C. Wilson

Försiktighet

I preserveChanges = true-scenariot, om RejectChanges-metoden anropas på en post i måldatasetet, återgår den till de ursprungliga uppgifterna från källdatasetet. Det innebär att om du försöker uppdatera den ursprungliga datakällan med måldatauppsättningen kanske den inte kan hitta den ursprungliga raden som ska uppdateras. Du kan förhindra en samtidighetsöverträdelse genom att fylla i en annan datauppsättning med de uppdaterade posterna från datakällan och sedan utföra en sammanslagning för att förhindra en samtidighetsöverträdelse. (En samtidighetsöverträdelse inträffar när en annan användare ändrar en post i datakällan efter att datamängden har fyllts i.)

Uppdatera begränsningar

Om du vill göra ändringar i en befintlig datarad lägger du till eller uppdaterar data i de enskilda kolumnerna. Om datamängden innehåller begränsningar (till exempel sekundärnycklar eller icke-nullbara begränsningar) är det möjligt att posten tillfälligt kan vara i ett feltillstånd när du uppdaterar den. Det vill säga det kan vara i ett feltillstånd när du har uppdaterat en kolumn men innan du kommer till nästa.

För att förhindra överträdelser av begränsningar kan du tillfälligt pausa begränsningar vid uppdateringar. Detta har två syften:

  • Det förhindrar att ett fel utlöses när du har uppdaterat en kolumn men inte har börjat uppdatera en annan.

  • Det förhindrar att vissa uppdateringshändelser genereras (händelser som ofta används för validering).

Anmärkning

I Windows Forms pausar databindningsarkitekturen som är inbyggd i datagrid-begränsningskontrollen tills fokus flyttas från en rad och du behöver inte uttryckligen BeginEditanropa metoderna , EndEditeller CancelEdit .

Begränsningar inaktiveras automatiskt när Merge metoden anropas på en datauppsättning. När sammanfogningen är klar utlöses en ConstraintException om det finns några begränsningar för datauppsättningen som inte kan aktiveras. I det här fallet är egenskapen EnforceConstraints inställd på false, och alla begränsningsöverträdelser måste lösas innan EnforceConstraints egenskapen återställs till true.

När du har slutfört en uppdatering kan du återaktivera begränsningskontrollen, vilket också återaktiverar uppdateringshändelser och initierar dem.

Mer information om hur du pausar händelser finns i Inaktivera begränsningar när du fyller i en datauppsättning.

Uppdateringsfel för dataset

När du uppdaterar en post i en datamängd finns det en möjlighet till fel. Du kan till exempel oavsiktligt skriva data av fel typ till en kolumn eller data som är för långa eller data som har något annat integritetsproblem. Eller så kan du ha programspecifika valideringskontroller som kan generera anpassade fel under alla steg i en uppdateringshändelse. Mer information finns i Verifiera data i datauppsättningar.

Underhålla information om ändringar

Information om ändringarna i en datamängd bevaras på två sätt: genom att flagga rader som anger att de har ändrats (RowState) och genom att behålla flera kopior av en post (DataRowVersion). Med hjälp av den här informationen kan processer avgöra vad som har ändrats i datamängden och skicka lämpliga uppdateringar till datakällan.

Egenskapen RowState

Egenskapen RowState för ett DataRow objekt är ett värde som ger information om status för en viss rad med data.

I följande tabell beskrivs möjliga värden för DataRowState uppräkningen:

DataRowState-värde Beskrivning
Added Raden har lagts till som ett objekt i en DataRowCollection. (En rad i det här tillståndet har ingen motsvarande ursprunglig version eftersom den inte fanns när den senaste AcceptChanges metoden anropades).
Deleted Raden har tagits bort med hjälp Delete av ett DataRow objekt.
Detached Raden har skapats men ingår inte i någon DataRowCollection. Ett DataRow objekt är i det här tillståndet omedelbart efter att det har skapats, innan det har lagts till i en samling och efter att det har tagits bort från en samling.
Modified Ett kolumnvärde på raden har ändrats på något sätt.
Unchanged Raden har inte ändrats sedan den senast anropades AcceptChanges.

DataRowVersion-uppräkning

Datauppsättningar lagrar flera versioner av register. Fälten DataRowVersion används när du hämtar värdet som finns i en DataRow med hjälp Item[] av egenskapen eller GetChildRows -metoden för DataRow objektet.

I följande tabell beskrivs möjliga värden för DataRowVersion uppräkningen:

DataRowVersion-värde Beskrivning
Current Den aktuella versionen av en post innehåller alla ändringar som har utförts på posten sedan den senaste gången AcceptChanges anropades. Om raden har tagits bort finns det ingen aktuell version.
Default Standardvärdet för en post, enligt definitionen i datamängdsschemat eller datakällan.
Original Den ursprungliga versionen av en post är en kopia av posten eftersom det var den senaste gången ändringarna checkades in i datauppsättningen. I praktiken är detta vanligtvis den version av en post som lästs in från en datakälla.
Proposed Den föreslagna versionen av en post som är tillgänglig tillfälligt när du är mitt i en uppdatering, det vill s. v.s. mellan den tid då du anropade BeginEdit metoden och EndEdit metoden. Du kommer vanligtvis åt den föreslagna versionen av en uppgift i en hanterare för en händelse, till exempel RowChanging. Om du anropar CancelEdit metoden återställs ändringarna och den föreslagna versionen av dataraden tas bort.

De ursprungliga och aktuella versionerna är användbara när uppdateringsinformation överförs till en datakälla. När en uppdatering skickas till datakällan finns vanligtvis den nya informationen för databasen i den aktuella versionen av en post. Information från den ursprungliga versionen används för att hitta posten som ska uppdateras.

I ett fall där primärnyckeln för en post ändras behöver du till exempel ett sätt att hitta rätt post i datakällan för att uppdatera ändringarna. Om ingen ursprunglig version fanns skulle posten troligen läggas till i datakällan, vilket inte bara resulterar i en extra oönskad post, utan i en post som är felaktig och inaktuell. De två versionerna används också i samtidighetskontroll. Du kan jämföra den ursprungliga versionen med en post i datakällan för att avgöra om posten har ändrats sedan den lästes in i datamängden.

Den föreslagna versionen är användbar när du behöver utföra verifieringen innan du genomför ändringarna i datauppsättningen.

Även om posterna har ändrats finns det inte alltid ursprungliga eller aktuella versioner av just den raden. När du infogar en ny rad i tabellen finns det ingen ursprunglig version, bara en aktuell version. På samma sätt finns det en ursprunglig version, men ingen aktuell version, om du tar bort en rad genom att anropa tabellens Delete metod.

Du kan testa om det finns en specifik version av en post genom att köra frågor mot en datarads HasVersion metod. Du kan komma åt båda versionerna av en post genom att skicka ett DataRowVersion uppräkningsvärde som ett valfritt argument när du begär värdet för en kolumn.

Hämta ändrade poster

Det är vanligt att inte uppdatera varje post i ett dataset. En användare kan till exempel arbeta med en Windows Forms-kontroll DataGridView som visar många poster. Användaren kan dock bara uppdatera några poster, ta bort en och infoga en ny. Datauppsättningar och datatabeller tillhandahåller en metod (GetChanges) för att endast returnera de rader som har ändrats.

Du kan skapa delmängder av ändrade poster med hjälp GetChanges av metoden för antingen datatabellen (GetChanges) eller själva datamängden (GetChanges). Om du anropar metoden för datatabellen returneras en kopia av tabellen med endast de ändrade posterna. Om du anropar metoden för datamängden får du på samma sätt en ny datauppsättning med endast ändrade poster i den.

GetChanges i sig returnerar alla ändrade poster. Genom att skicka den önskade DataRowState parametern till GetChanges metoden kan du däremot ange vilken delmängd av ändrade poster du vill ha: nyligen tillagda poster, poster som har markerats för borttagning, frånkopplade poster eller ändrade poster.

Det är användbart att hämta en delmängd av ändrade poster när du vill skicka poster till en annan komponent för bearbetning. I stället för att skicka hela datamängden kan du minska kostnaderna för att kommunicera med den andra komponenten genom att bara hämta de poster som komponenten behöver.

Spara ändringar i datamängden

När ändringar görs i datauppsättningen anges egenskapen RowState för ändrade rader. De ursprungliga och aktuella versionerna av register upprättas, underhålls och görs tillgängliga för dig av RowVersion egenskapen. Metadata som lagras i egenskaperna för dessa ändrade rader är nödvändiga för att skicka rätt uppdateringar till datakällan.

Om ändringarna återspeglar datakällans aktuella tillstånd behöver du inte längre underhålla den här informationen. Det finns vanligtvis två gånger när datauppsättningen och dess källa är synkroniserade:

  • Omedelbart efter att du har läst in information i datauppsättningen, till exempel när du läser data från källan.

  • När du har skickat ändringar från datauppsättningen till datakällan (men inte tidigare, eftersom du skulle förlora den ändringsinformation som krävs för att skicka ändringar till databasen).

Du kan committa de väntande ändringarna till datamängden genom att anropa metoden AcceptChanges. AcceptChanges Anropas vanligtvis vid följande tidpunkter:

  • När du har laddat in datauppsättningen. Om du läser in en datauppsättning genom att anropa TableAdapter-objektets metod Fill, sparar adaptern automatiskt ändringar åt dig. Men om du läser in en dataset genom att sammanfoga en annan dataset i den, måste du begå ändringarna manuellt.

    Anmärkning

    Du kan förhindra att adaptern automatiskt genomför ändringarna när du anropar Fill metoden genom att ange AcceptChangesDuringFill adapterns egenskap till false. Om den är inställd på false, ställs RowState för varje rad som infogas under fyllningsprocessen in till Added.

  • När du har skickat datauppsättningsändringar till en annan process, till exempel en XML-webbtjänst.

    Försiktighet

    Om du genomför ändringen på det här sättet raderas all ändringsinformation. Genomför inte ändringarna förrän du har slutfört de åtgärder som kräver att programmet vet vilka ändringar som har gjorts i datauppsättningen.

Den här metoden utför följande:

  • Skriver över den ursprungliga Current versionen av en post till dess Original version och ersätter den originella versionen.

  • Tar bort alla rader där egenskapen RowState är inställd på Deleted.

  • Anger egenskapen RowState hos en post till Unchanged.

Metoden AcceptChanges är tillgänglig på tre nivåer. Du kan anropa det på ett DataRow objekt för att spara ändringar för just den raden. Du kan också anropa det på ett DataTable objekt för att committa alla rader i en tabell. Slutligen kan du anropa det på DataSet-objektet för att verkställa alla väntande ändringar i alla poster i alla tabeller i datauppsättningen.

I följande tabell beskrivs vilka ändringar som åtagits beroende på vilket objekt metoden anropas på:

Metod Resultat
System.Data.DataRow.AcceptChanges Ändringar utförs endast på den specifika raden.
System.Data.DataTable.AcceptChanges Ändringar utförs på alla rader i den specifika tabellen.
System.Data.DataSet.AcceptChanges Ändringar utförs på alla rader i alla tabeller i datauppsättningen.

Anmärkning

Om du läser in en datauppsättning genom att anropa en TableAdapter-metod Fill behöver du inte uttryckligen acceptera ändringar. Standardmässigt anropar Fill metoden AcceptChanges efter att den har fyllt i datatabellen.

En relaterad metod, RejectChanges, ångrar effekten av ändringar genom att kopiera Original-versionen tillbaka till Current-versionen av poster. Den sätter tillbaka RowState av varje post till Unchanged.

Datavalidering

För att verifiera att data i ditt program uppfyller kraven för de processer som de skickas till måste du ofta lägga till validering. Det kan handla om att kontrollera att en användares post i ett formulär är korrekt, validera data som skickas till ditt program av ett annat program eller till och med kontrollera att den information som beräknas inom din komponent faller inom kraven för datakällan och programmet.

Du kan verifiera data på flera sätt:

  • I affärsskiktet genom att lägga till kod i ditt program för att verifiera data. Datauppsättningen är en plats där du kan göra detta. Datamängden ger några av fördelarna med serverdelsverifiering – till exempel möjligheten att verifiera ändringar när kolumn- och radvärden ändras. Mer information finns i Verifiera data i datauppsättningar.

  • I presentationsskiktet genom att lägga till validering i formulär. Mer information finns i Verifiering av användarindata i Windows-formulär.

  • Genom att skicka data till en datakälla, till exempel en databas, och låta den acceptera eller avvisa datan i backend-delen. Om du arbetar med en databas som har avancerade funktioner för att verifiera data och tillhandahålla felinformation kan detta vara en praktisk metod eftersom du kan verifiera data oavsett var de kommer ifrån. Den här metoden kanske inte uppfyller programspecifika valideringskrav. Om datakällan validerar data kan det dessutom leda till flera resor till datakällan, beroende på hur programmet hanterar valideringsfel som genereras av backend.

    Viktigt!

    När du använder datakommandon med en CommandType egenskap som är inställd på Textkontrollerar du noggrant information som skickas från en klient innan du skickar den till databasen. Skadliga användare kan försöka skicka (mata in) ändrade eller ytterligare SQL-instruktioner i ett försök att få obehörig åtkomst eller skada databasen. Innan du överför användarindata till en databas kontrollerar du alltid att informationen är giltig. Det är en bra idé att alltid använda parametriserade frågor eller lagrade procedurer när det är möjligt.

Överföra uppdateringar till datakällan

När ändringar har gjorts i en datauppsättning kan du överföra ändringarna till en datakälla. Oftast gör du detta genom att anropa Update metoden för en TableAdapter (eller dataadapter). Metoden loopar igenom varje post i en datatabell, avgör vilken typ av uppdatering som krävs (uppdatera, infoga eller ta bort), om någon, och kör sedan rätt kommando.

Som en illustration av hur uppdateringar görs antar vi att ditt program använder en datauppsättning som innehåller en enda datatabell. Programmet hämtar två rader från databasen. Efter hämtningen ser den minnesinterna datatabellen ut så här:

(RowState)     CustomerID   Name             Status
(Unchanged)    c200         Robert Lyon      Good
(Unchanged)    c400         Nancy Buchanan    Pending

Ditt program ändrar Nancy Buchanans status till "Preferred". Som ett resultat av den här ändringen ändras värdet för egenskapen för den RowState raden från Unchanged till Modified. Värdet för RowState egenskapen för den första raden förblir Unchanged. Datatabellen ser nu ut så här:

(RowState)     CustomerID   Name             Status
(Unchanged)    c200         Robert Lyon      Good
(Modified)     c400         Nancy Buchanan    Preferred

Programmet anropar Update nu metoden för att överföra datamängden till databasen. Metoden inspekterar varje rad i tur och ordning. För den första raden överför metoden ingen SQL-instruktion till databasen eftersom den raden inte har ändrats sedan den ursprungligen hämtades från databasen.

För den andra raden Update anropar metoden dock automatiskt rätt datakommando och överför det till databasen. Den specifika syntaxen för SQL-instruktionen beror på den dialekt av SQL som stöds av det underliggande datalagret. Men följande allmänna egenskaper i den överförda SQL-instruktionen är anmärkningsvärda:

  • Den överförda SQL-instruktionen är en UPDATE instruktion. Adaptern vet att använda en UPDATE -instruktion eftersom värdet för RowState egenskapen är Modified.

  • Den överförda SQL-instruktionen innehåller en WHERE sats som anger att målet för -instruktionen UPDATE är raden där CustomerID = 'c400'. Den här delen av uttrycket SELECT skiljer målraden från alla andra eftersom CustomerID är primärnyckeln i måltabellen. Informationen för WHERE -satsen härleds från den ursprungliga versionen av posten (DataRowVersion.Original), om de värden som krävs för att identifiera raden har ändrats.

  • Den överförda SQL-instruktionen SET innehåller -satsen för att ange de nya värdena för de ändrade kolumnerna.

    Anmärkning

    Om egenskapen TableAdapter har angetts UpdateCommand till namnet på en lagrad procedur konstruerar inte adaptern någon SQL-instruktion. I stället anropas den lagrade proceduren med lämpliga parametrar som skickas in.

Skicka parametrar

Du använder vanligtvis parametrar för att skicka värdena för poster som ska uppdateras i databasen. När TableAdapter-metoden Update kör en UPDATE -instruktion måste den fylla i parametervärdena. Den hämtar dessa värden från Parameters samlingen för lämpligt datakommando – i det här fallet UpdateCommand objektet i TableAdapter.

Om du har använt Visual Studio-verktygen för att generera en dataadapter, innehåller UpdateCommand-objektet en samling parametrar som motsvarar varje parameterplats i instruktionsbladet.

Egenskapen System.Data.SqlClient.SqlParameter.SourceColumn för varje parameter pekar på en kolumn i datatabellen. Egenskapen SourceColumn för parametrarna au_id och Original_au_id är till exempel inställd på den kolumn i datatabellen som innehåller författarens ID. När adapterns metod Update körs läser den kolumnen för författarens ID från posten som uppdateras och infogar värdena i instruktionen.

I ett UPDATE uttryck måste du ange både de nya värdena (de som skrivs till databasposten) samt de gamla värdena (så att databasposten kan finnas i databasen). Det finns därför två parametrar för varje värde: en för SET -satsen och en annan för WHERE -satsen. Båda parametrarna läser data från posten som uppdateras, men de får olika versioner av kolumnvärdet baserat på parameterns SourceVersion egenskap. Parametern för SET -satsen hämtar den aktuella versionen och parametern WHERE för -satsen hämtar den ursprungliga versionen.

Anmärkning

Du kan också ange värden i Parameters samlingen själv i kod, vilket du vanligtvis gör i en händelsehanterare för datakortets RowChanging händelse.