Download de presentatie
De presentatie wordt gedownload. Even geduld aub
GepubliceerdMathijs Willems Laatst gewijzigd meer dan 10 jaar geleden
1
Addendum – ADO.NET ADO.NET : het object model .NET Data Providers
Connecteren met een database : Connection Uitvoeren van SQL Query : Command Lezen van data : De DataReader De DataAdapter De DataSet ADO.NET is een verzameling van klassen dat .NET applicaties toelaat gegevens in een data source te lezen en aan te passen. Je habt toegang tot die klassen via de System.Daytta Namespace in het .NET Framewordk./ ADO.NET geeft geen continu open verbinding meer nodig met de database In de traditionele client/server toepassingen maken clients een verbinding met de server en houden die verbinding open zolang de applicatie draait. Dit is fout om verscheidene redenen Open database connections take up valuable system resources. In most cases, databases can maintain only a small number of concurrent connections. The overhead of maintaining these connections detracts from overall application performance. Similarly, applications that require an open database connection are extremely difficult to scale up. An application that does not scale up well might perform acceptably with four users but will likely not do so with hundreds. ASP.NET Web applications in particular need to be easily scalable, because traffic to a Web site can go up by orders of magnitude in a very short period. In ASP.NET Web applications, the components are inherently disconnected from each other. The browser requests a page from the server; when the server has finished processing and sending the page, it has no further connection with the browser until the next request. Under these circumstances, maintaining open connections to a database is not viable, because there is no way to know whether the data consumer (the client) requires further data access. A model based on always-connected data can make it difficult and impractical to exchange data across application and organizational boundaries using a connected architecture. If two components need to share the same data, both have to be connected, or a way must be devised for the components to pass data back and forth. For all these reasons, data access with ADO.NET is designed around an architecture that uses connections sparingly. Applications are connected to the database only long enough to fetch or update the data. Because the database is not holding on to connections that are largely idle, it can service many more users. Visual Basic.NET
2
ADO.NET Het ADO.Net Object model Visual Basic.NET
3
.NET Data Providers Alle toegang in ADO.NET tot data sources gebeurt o.b.v. .NET Data providers. Is een verzameling klassen die code in staat stelt om met een specifieke gegevensbron te communiceren om gegevens op t ehalen, te bewerken. .NET Framework bevat 2 .NET Data Providers SQL Server Data Provider: geoptimaliseerde toegang tot SQL Server Geimplementeerd in de System.Data.SqlClient Namespace OLEDB Data Provider : toegang tot alle gegevensbronnen waarvoor OLE DB provider geinstalleerd Geimplementeerd in de System.Data.OleDb Namespace Vereisen installatie van MDAC 2.7 of later Importeer namespace .NET Data Provider in project Imports System.Data.SqlClient Imports System.Data.OleDb Data Provider DATA Providers bevatten tools die toelaten data te lezen en aan te passen in een multi tier omgeving. De meeste objecten in beide labraries zijn hetzelfde, maar worden geidentificeerd door de prefix. Bv SQLDataReader en OLEDBDataReader SQL Server Data Provider : is een provider geoptimaliseerd voor SQL server versie 7 en verder. Gebruikt achter de schermen een protocol TDS(Tabular Data Stream genaamd) voor de communicatie tussen client en SQL Server. De SQL Data Provider maakt rechtstreeks gebruik van protocol en maakt nooit gebruik van OLEDB, ADO; Als je SQL Server gebruikt, moet je die provider gebruiken owv performantie redenen. een generieke provider die met elke OLE DB gegevensbron kan communiceren. Deze provider ondersteunt de toegang tot OLEDB2.5 interfaces niet. Dit betekent dat Microsoft OLE DB Provider voor Exchange niet kan gebruikt worden met OLE DB.NET. Bovendien is deze provider niet compatibel met de OLE DB Provider voor ODBC. Je kan van de site de .NET provider voor ODBC downloaden. Op korte termijn worden ook data providers verwacht voor andere databases zoals Oracle (bestaat reeds) en DB2. De 2 data providers die bij het .NET framework worden geleverd, bevatten dezelfde objecten, al verschillen de namen en sommige eigenschappen en methodes. Zo beginnen de namen van SQL Server provider met SQL en deze van de OLEDB provider met OLEDB. A data provider in the .NET Framework serves as a bridge between an application and a data source and is used to retrieve data from a data source and to reconcile changes to that data back to the data source. The Connection, Command, DataReader, and DataAdapter objects represent the core elements of the .NET data provider model. An Open Database Connectivity (ODBC) .NET Data Provider is available as a separate download at The download includes documentation on the classes that make up the ODBC .NET Data Provider. However, the implementation has the same architecture as both the SQL Server .NET Data Provider and the OLE DB .NET Data Provider. As a result, you can apply the information found in this section to the ODBC .NET Data Provider as well. The SQL Server .NET Data Provider uses its own protocol to communicate with SQL Server. It is lightweight and performs well because it is optimized to access a SQL Server directly without adding an OLE DB or Open Database Connectivity (ODBC) layer. The following illustration contrasts the SQL Server .NET Data Provider with the OLE DB .NET Data Provider. The OLE DB .NET Data Provider communicates to an OLE DB data source through both the OLE DB Service component, which provides connection pooling and transaction services, and the OLE DB Provider for the data source. The OLE DB .NET Data Provider uses native OLE DB through COM interop to enable data access. The OLE DB .NET Data Provider supports both manual and automatic transactions. For automatic transactions, the OLE DB .NET Data Provider automatically enlists in a transaction and obtains transaction details from Windows 2000 Component Services. To use the OLE DB .NET Data Provider, you must use an OLE DB provider that supports the OLE DB interfaces listed in OLE DB Interfaces Used by the OLE DB .NET Data Provider. Support for the OLE DB Provider for ODBC (MSDASQL) is disabled. For access to Open Database Connectivity (ODBC) data sources, an ODBC .NET Data Provider is available as a separate download at Visual Basic.NET
4
Connecteren met een database
Connecteren met de database : Connection Object Connections zijn verantwoordelijk voor het onderhouden van de fysieke verbinding tussen gegevensbron en .NET applicatie Elke Data Provider implementeert eigen versie van connection klasse SqlConnection in namespace System.Data.SQLClient OleDBConnection in namespace System.Data.OleDb Connection Object Data Provider De eerste stap in gegevenstoiegang in een database is natuurlijk het maken van een verbinding. Elke applicatie die data wenst te lezen uit een data source zal eerst een verbinding met de datasource moeten openen. In ADO.NET kan je een connectie maken en beheren gebruik makend van SQLConnection of OleDbConnection object. Je kiest het connection object in functie van de data provider waarmee je wenst te connecteren. Daar het Connection object onderdeel is van de data provider implementeert elke Data Provider zijn eigen versie. De 2 Data Providers ondersteunt in .NET framework implementeren de OleDbConnection in de namespace System.Data.OleDb en SQLConnection in de namespace System.Data.SQLClient. The SqlConnection object is geoptimalizeerd voor SQL Server 7.0 of later en gaat niet door de OLEDB provider maar gaat rechtstreeks naar de SQL Server, waardoor efficienter. De OleDbConnection object gebruikt OLEDB to expose a consistent API for a variety of data sources — everything from simple text files to spreadsheets and, of course, full-featured databases. Omdat ADO.NET het ADO objectmodel samenvoegt met OLE DB is het vanwege de prestaties nog zelden nodig rechtstreeks naar OLE DB te gaan. In tegenstelling tot ADO kan je een Connection niet gebruiken om SQL statements uit te voeren. De connection klasse gebruik je enkel om verbinding te openen, sluiten Het instellen of ophalen van eigenschappen van een verbinding Het afhandelen van aan een verbinding zelf gerelateerde events Visual Basic.NET
5
Connecteren met een database
Connecteren met een data source via OleDbConnection Stel connection type in Dim oConn as New OleDbConnection() Geef data source op. ConnectionString property bevat de string die gebruikt wordt om de verbinding met de gegevensbron te maken als de methode open wordt uitgevoerd oConn.ConnectionString =“Provider=Microsoft.Jet.OLEDB.4.0;Data Source =“ & Application.StartUpPath & “\northwind.mdb” Connecteer met data source oConn.Open() Sluiten van verbinding If (not oConn is Nothing) AndAlso (oConn.State = ConnectionState.Open) then oConn.close End If Opm : Niet vergeten want verbindingen worden niet automatisch gesloten als ze de scope verliezen In het vorige hoofdstuk hebben we een connection object gemaakt aan de hand van de Data Adapter Wizard. Hier kijken we naar de andere manieren ConnectionString : bevat de string die gebruikt wordt om de verbinding met de gegevensbron te maken als de methode open wordt uitgevoerd. Alle ConnectionStrings bevatten dezelfde indeling. Ze bestaan uit een reeks sleutelwoorden en waarden, gescheiden door een puntkomma “keyword=value;keyword=value;” De namen van de sleutelwoorden zijn hoofdlettergevoelig. De waarden daarentegen niet. Open : dit zorgt ervoor dat de gespecifieerde provider geladen wordt en dat de verbinding met db geopend wordt. Voorbeeld : Dim nwindConn As OleDbConnection = New OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;" & _ "Integrated Security=SSPI;Initial Catalog=northwind") nwindConn.Open() Sluiten van verbinding : Je moet altijd de Connection sluiten als je hem niet meer nodig hebt. Dit kan je doen gebruik makend van de Close of Dispose methods van het Connection object. Connections worden NIET impliciet vrijgegeven wanneer het connection object out of scope gaat of reclaimed door garbage collector. Geopende verbindingen worden niet teruggeven aan de verbindingspool, zodat ze niet automatisch beschikbaar eijn voor andere clients. Dit zou betekenen dat je applicatie niet in staat is op een effectieve wijze grote aantallen gebruikers af te handelen zonder dat hierbij de prestaties verminderen. Visual Basic.NET
6
Connecteren met een database
Of verkort op basis van constructor Dim strConn = =“Provider=Microsoft.Jet.OLEDB.4.0;Data Source =“ & Application.StartUpPath & “\northwind.mdb” Dim oConn as New OleDbConnection(strConn) oConn.Open oConn.Close Visual Basic.NET
7
Connecteren met een database
De connectionstring (formaat afhankelijk van namespace SqlClient of OleDB) SqlConnection “Data Source =name or IP adress server;Password=password;User ID=userID;Initial Catalog=databasename;Integrated Security=True” OleDbConnection (inhoud afhankelijk van OleDb Provider) Hard gecodeerd Microsoft Access 2000 "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=physical path to mdb file;Password=password;User ID=userID; SQL Server "Provider=SQLOLEDB;Data Source=name or IP adress server;Password=password; User ID=userID;Initial Catalog=databasename;Integrated Security=True” Oracle "Provider=MSDAORA;Data Source=name server;Password=password;User ID=userID; Initial Catalog = databasename; De indeling van de connectionstring is uniek per Data Provider. Bvb SqlConnection kent geen Provider keyword Je kan altijd een beetje zeuren door het dialoogvenster Data Link Properties te gebruiken om een verbinding tijdens de ontwerpfase te maken en vervolgens de waarde te kopieren. De connectionstring kan je enkel instellen als de Connection gesloten is. De Connectionstring wordt volledig gevalideerd bij het openen. Van zodra Connection een ongeldige of niet ondersteunde eigenschap aantreft wordt een uitzondering (OleDbException of SQLDBException) gegenereerd. Integrated security : Moet de connectie gemaakt worden gebruik makend van integrated security of SQL Server security. Mogelijke waarden zijn True, False of SSPI(is hetzelfde als true) De SQLClient Data Provider maakt automatiscg gebruik van connection pooling. Maar de connectionstring moet exact hetzelfde zijn om in dezelfde pool te gaan (kleine verschillen zoals een blanco maken een verschil uit) Kan je controleren in de connectionstring nl via de keywords Max Pool Size, Min Pool Size, Pooling Connections worden in de pool geplaatst als je de close of dispose methode aanroept van het connection object Visual Basic.NET
8
Connecteren met een database
Via UDL file (Microsoft Data Link file) Ga naar Windows Explorer Dubbelklik bin directory van project Rechtermuisklik in rechter venster > File > New > Text document Rename gecreeerde tekst bestand. Pas extensie aan in .udl, en geef een duidelijke naam bvb Northwind.udl Dubbelklik bestand. Het Data Link Property dialoogvenster verschijnt. Openen van connection o.b.v. Udl file "File Name=" & Application.StartupPath & "\northwind.udl“ Opmerking : maak zoveel mogelijk gebruik van trusted verbindingen (via Windows verificatie) Using Universal Data Link (UDL) files may slow performance. You can use UDL files to supply OLE DB connection information to the OLE DB .NET Data Provider. However, because UDL files can be modified externally to any ADO.NET client program, connection strings that contain references to UDL files will be parsed every time the connection is opened. This can slow performance and it is therefore recommended, for best performance, that you use a static connection string that does not include a UDL file. Voordeel Windows autheticatie : eenvoudiger te onderhouden, no username en paswoord in connection string en paswoorden dienen niet over het netwerk te worden verstuurd. Gebruik geen impersonation in de data Access Layer Visual Basic.NET
9
Connecteren met een database
Connection Properties Database of Initial Catalog: de naam van de database die moet worden geopend zodra de verbinding tot stand komt DataSource : de naam server of locatie van bestand dat de database bevat ConnectionString : connectionstring gebruikt voor maken verbinding ConnectionTimeOut : de maximale tijd(in seconden) dat het connection object probeert verbinding te maken vooraleer een foutmelding verschijnt (default 15 sec) Provider (enkel igv OleDbConnection) : Naam OleDB Data Provider State : status huidige connectie Closed : gesloten. (Status na uitvoeren Close methode) Open : open en actief (Status na uitvoeren Open methode) Broken : connectie is niet meer bruikbaar (netwerk probleem,...) Connecting : connectie is bezig verbinding te maken Executing : de connection voert een Command uit Fetching : De connection haalt gegevens op Opm : allen read-only, behalve connectionstring De 2 versies van het connection object bevatten een iets andere reeks van eigenschappen. Provider bvb bestaat enkel voor OleDb. Connectionstring is de belangrijkste eigenschap. In feite kan je de andere eigenschappen alleen lezen. Ze worden ingesteld door de connection adhv de waarden die je opgeeft on de connectionstring. Visual Basic.NET
10
Connecteren met een database
Connection Events StateChanged : als toestand van object Connection verandert Geeft een StateChangeEventArgs door aan handler met 2 eigenschappen (mogelijke waarden idem property State) CurrentState OriginalState Voorbeeld Dim theMessaqe as String theMessage = “The connection is changing from “ & _ e.OriginalState.ToString & “ to “ & _ e.CurrentState.ToString Messagebox.Show(theMessage) De 2 versies van het connection object bevatten een iets andere reeks van eigenschappen. Provider bvb bestaat enkel voor OleDb. Connectionstring is de belangrijkste eigenschap. In feite kan je de andere eigenschappen alleen lezen. Ze worden ingesteld door de connection adhv de waarden die je opgeeft on de connectionstring. Visual Basic.NET
11
Connecteren met een database
Opvangen van fouten Try oConn = New OleDbConnection() oConn.connectionstring =“Provider=Microsoft.Jet.OLEDB.4.0;Data Source =“ & Application.StartUpPath & “\northwind.mdb” oConn.Open() Catch ex As OleDbException Messagebox.Show(ex. Message) Next End Try Van zodra Connection bij het openen een ongeldige of niet ondersteunde eigenschap aantreft wordt een uitzondering (OleDbException of SQLDBException) gegenereerd. Connection Pooling : de SQL Client Data Provider valt terug op de Windows 2000 Component Services voor connection pooling. De OLEDB provider pools connectie sgebruik makend van OLEDB Session Pooling Catch ex As OleDbException Dim i As Integer For i = 0 to ex.Errors.Count – 1 Messagebox.Show(ex.Errors(i).Message) Next End Try Visual Basic.NET
12
Connecteren met een database
Tip voor maken van een verbinding tijdens het ontwerpen Open de Server Explorer Klik op de knop Connect to Database. Het Data Link Property dialoogvenster verschijnt Na instellen van Provider en Connection details, klik op OK. De connectie wordt toegevoegd aan de Server Explorer Nu kan je de inhoud van db bekijken en eventueel via drag drop een connection object op form aanmaken De server explorer biedt de mogelijkheid tijdens ontwerpfase verbindingen te bekijken en te onderhouden met een aantal systeemservices, waaronder event logs, message queues,... Maar ook data Connections. Visual Basic.NET
13
Uitvoeren van SQL instructie
Uitvoeren SQL (SELECT, INSERT, UPDATE, DELETE, DDL of DCL) of Stored Procedure : Command object Is .NET Data Provider afhankelijk SQLCommand OleDbCommand Connection Object Data Provider Command Uitvoeren SQL statement 1. 2. Command is een SQL instructie of verwijzing naar een SP dier op een connection object wordt uitgevoerd. Behalve gegevens ophalen en bewerken kan je via command object ook bepaalde zoekopdrachten uitvoeren op gegevensbron die geen resultaatreeks teruggeven of DDL opdrachten uitvoeren om structuur gegevensbron te wijzigen. Je dient minimaal de commandtext en connection property op te geven. De execute methode voert de tekst uit in de commandtext. Visual Basic.NET
14
Uitvoeren van SQL instructie
Creatie Command object Dim oCmd As New OleDbCommand() Opgave van het uit te voeren SQL Statement of Stored Procedure Dim strSQL as String strSQL = "select categoryid, categoryName from categories“ oCmd.CommandText = strSQL oCmd.CommandType = CommandType.Text Opgave van connectie waarop de Command moet worden uitgevoerd oCmd.Connection = oConn Uitvoeren SQL Statement of Stored Procedure Igv Select Dim oDR as OleDbDataReader oDR = oCmd.ExecuteReader() Igv Update, Insert, Delete (je krijgt geen resultaat terug) oCmd.ExecuteNonQuery() Of verkort 2, 3 via constructor : oCmd = New OleDbCommand(strSQL,oConn) Als je het resultaat wenst te plaatsen in een DatAReader object gebruik je de executeReader methode. Het is ook altijd goed om het command type mee te geven. Als je weet dat de uitvoering van je SQL Query geen rijen retourneert moet je ExecuteNonQuery gebruiken Visual Basic.NET
15
Uitvoeren van SQL instructie
Command properties CommandText : de SQL instructie of stored procedure die moet worden uitgevoerd CommandTimeOut : de wachttijd(in seconden) op een reactie van de gegevensbron CommandType : geeft aan hoe de Commandtext property geinterpreteerd moet worden. Mogelijke waarden : Text(default), TableDirect, StoredProcedure Connection : het connection object waarop de Data Command moet worden uitgevoerd Parameters : de verzameling Parameters voor SQL instructie of Stored Procedure Transaction : het object Transaction waarbinnen de opdracht wordt uitgevoerd UpdatedRowSource : bepaalt hoe de resultaten worden toegepast op een rij als de Command wordt gebruikt door de methode Update van de DataAdapter Visual Basic.NET
16
Uitvoeren van SQL instructie
Uitvoeren van Query of stored procedure Via de Command methodes ExecuteNonQuery : voert een opdracht op Connection uit en geeft het aantal rijen terug dat daardoor wordt beïnvloed; Gebruik dit wanneer SQL statement geen resultaat retourneert nl bij INSERT, UPDATE of DELETE Voorbeeld SQL Statements UPDATE Customers SET CompanyName = 'NewCompanyName' WHERE CustomerID = 'ALFKI' INSERT INTO Customers (CustomerID, CompanyName) VALUES ('NewID', 'NewCustomer') DELETE FROM Customers WHERE CustomerID = 'ALFKI' Er bestaan ook nog methodes ExecuteScalar : igv aggregate functie met 1 rij en 1 KOLOM Executexmlreader : xml (query bevat dan FOR XML) enkel igv sqlclient Visual Basic.NET
17
Uitvoeren van SQL instructie
Voorbeeld programmacode Dim oConn As New OleDbConnection() Dim oCmd As OleDbCommand Dim strSQL As String Dim strConn As String ‘Maken database verbinding strConn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source =" & _ Application.StartupPath & "\northwind.mdb" oConn.Connectionstring = strConn oConn.Open() ‘Creatie SQL Statement strSQL = "UPDATE Customers" strSQL &= " SET CompanyName = 'NewCompanyName'" strSQL &= " WHERE CustomerID = 'ALFKI'" oCmd = New OleDbCommand(strSQL, oConn) ‘Uitvoeren SQL Statement Dim intRecordsAffected As Integer intRecordsAffected = oCmd.ExecuteNonQuery() If intRecordsAffected = 1 Then MessageBox.Show("Update succeeded") Else 'Assume intRecordsAffected = 0 MessageBox.Show("Update failed") End If oConn.Close() Er bestaan ook nog methodes ExecuteScalar : igv aggregate functie met 1 rij en 1 KOLOM Executexmlreader : xml (query bevat dan FOR XML) enkel igv sqlclient Visual Basic.NET
18
Uitvoeren van SQL instructie
ExecuteReader : voert de instructie uit op het Connection object en stelt een DataReader samen die het resultaat bevat. Voorbeeld SQL Statement "SELECT CustomerID, CompanyName FROM Customers" Er bestaan ook nog methodes ExecuteScalar : igv aggregate functie met 1 rij en 1 KOLOM Executexmlreader : xml (query bevat dan FOR XML) enkel igv sqlclient Visual Basic.NET
19
Uitvoeren van SQL instructie
Voorbeeld programmacode Dim oConn As OleDbConnection() Dim oCmd As OleDbCommand Dim strSQL As String Dim strConn As String ‘Maken database verbinding strConn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source =" & _ Application.StartupPath & "\northwind.mdb" oConn = New OleDbConnection(strConn) oConn.Open() ‘Creatie SQL Statement strSQL = "SELECT CustomerID, CompanyName FROM Customers" oCmd = New OleDbCommand(strSQL, oConn) ‘Uitvoeren SQL Statement en doorlopen resultaatset Dim oDR As OleDbDataReader = oCmd.ExecuteReader() Dim strMsg As String While oDR.Read() strMsg &= oDR.Item("CustomerID") & " – " & oDR.Item("CompanyName") strMsg &= vbCrLf End While ‘Sluit DataReader!!!!! oDR.Close() MessageBox.Show(strMsg) oConn.Close() Note that the code calls the Read method before reading the first row of the result set because the first row is not available immediately after you call ExecuteReader. This represents a change from previous object models such as ADO. The DataReader that the Command object returns does not make the first row of data available until you call the Read method. Visual Basic.NET
20
Uitvoeren van SQL instructie
ExecuteScalar Als de query 1 resultaat retourneert Count(*), Avg(UnitsInStock),... Laat toe de waarde in 1 stap op te halen Strsql=“select count(*) from Customers” Dim oCcmd as new OleDbCommand(strSQL, oConn) Dim aantal as integer aantal=oCmd.executeScalar() Visual Basic.NET
21
Uitvoeren van SQL instructie
Gebruik van parameters 3 stappen Parameters opgeven in de query Parameters opgeven in de verzameling Parameters Waarden aan parameters opgeven Opgeven Query In OleDbCommand : ? oCmd.CommandText = “Select * from customers where customerID = ?” In SqlDbCommand : benoemde parameters oCmd.CommandText= “Select * from customers where customerID Toevoegen parameters aan verzameling Parameters oCmd.Parameters.Add(“CustomerID", OleDbType.WChar, 5) Instellen Parameterwaarden oCmd.parameters(“CustomerID”).value = .... Visual Basic.NET
22
Uitvoeren van SQL instructie
Voorbeeld programmacode Dim oConn As OleDbConnection() Dim oCmd As OleDbCommand Dim strSQL As String Dim strConn As String ‘Maken database verbinding strConn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source =" & _ Application.StartupPath & "\northwind.mdb" oConn = new OleDbConnection(strConn) oConn.Open() ‘Creatie SQL Statement en Parameters strSQL = "SELECT CustomerID, CompanyName FROM Customers" strSQL &= " WHERE CustomerID = ?" oCmd = New OleDbCommand(strSQL, oConn) oCmd.Parameters.Add("CustomerID", OleDbType.WChar, 5) oCmd.Parameters("CustomerID").Value = "ALFKI“ ‘Uitvoeren SQL Statement en doorlopen resultaatset Dim oDR As OleDbDataReader = oCmd.ExecuteReader() Dim strMsg As String While oDR.Read() strMsg &= oDR.Item("CustomerID") & " – " & oDR.Item("CompanyName") strMsg &= vbCrLf End While oDR.Close() MessageBox.Show(strMsg) oConn.Close() Note that the code calls the Read method before reading the first row of the result set because the first row is not available immediately after you call ExecuteReader. This represents a change from previous object models such as ADO. The DataReader that the Command object returns does not make the first row of data available until you call the Read method. Visual Basic.NET
23
Uitvoeren van SQL instructie
Voorbeeld : Product Information Maak nieuwe Windows Applicatie met naam Products Creëer form Codeer Load event van form Private Sub frmProduct_Load( ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ListLoad() End Sub Codeer ListLoad procedure Visual Basic.NET
24
Uitvoeren van SQL instructie
Private Sub ListLoad() Dim oConn As OleDbConnection Dim oCmd As OleDbCommand Dim oDr As OleDbDataReader Dim strSQL As String = "Select ProductName from Products" Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source =" & .... Try oConn = New OleDbConnection(strConn) oCmd = New OleDbCommand(strSQL, oConn) oConn.Open() oDr = oCmd.ExecuteReader() lstProducts.Items.Clear() Do While oDr.Read() lstProducts.Items.Add(oDr.Item("ProductName")) Loop oDR.Close() Catch ex As OleDbException MessageBox.Show(ex.Message) Finally If (Not oConn Is Nothing) AndAlso (oConn.State = ConnectionState.Open) Then oConn.close() End Try End Sub Uitvoeren van SQL instructie Als je het resultaat wenst te plaatsen in een DatAReader object gebruik je de executeReader methode. Het is ook altijd goed om het command type mee te geven. Als je weet dat de uitvoering van je SQL Query geen rijen retourneert moet je ExecuteNonQuery gebruiken Visual Basic.NET
25
Lezen van Data : De DataReader
Kenmerken DataReader is forward-only en read-only data Kan slechts 1 keer gebruikt worden Rijen worden 1/1 in geheugen geladen DataReader kan niet gebruikt worden als DataSource!! Afhankelijk van .NET Data Provider Hoe gebruiken? Call Command.ExecuteReader Itereer door data met DataReader.Read Lees Kolom data Sluit DataReader!!!!! Data Provider 1. Connection Object Uitvoeren SQL statement 2. Command Object Levert een forward-only, read-only stream met resultaatset van uitgevoerde query. Dit betekent dat de resultaatset moet doorlopen worden van begin naar einde en dat updates onmogelijk zijn. Je hebt met een datareader ook maar 1 record/keer in geheugen. Gegeven deze beperkingen zou je kunnen denken dat het gebruik van datareader eerder beperkt is. Dit is zeker niet het geval. Stel dat een SQL statement meer dan 1000 rijen retourneert naar de client aaplicatie. Dit zou betekenen dat hij deze allemaal in het geheugen moet bijhouden alvorens ze op het scherm getoond kunnen worden. Wat een waste of memory betekent. Note that the code calls the Read method before reading the first row of the result set because the first row is not available immediately after you call ExecuteReader. This represents a change from previous object models such as ADO. The DataReader that the Command object returns does not make the first row of data available until you call the Read method. 3. DataReader Object Visual Basic.NET
26
De DataReader Creatie DataReader Doorlopen van DataReader
Dim oDRAs OleDbDataReader .... oDR=oCmd.ExecuteReader() Doorlopen van DataReader Do While oDR.Read Messagebox.Show(oDR(0).ToString & ...) Loop Sluiten DataReader (niet vergeten!!) oDR.Close() Opmerking : Zolang DataReader object niet afgesloten, kan geen enkele SQL query nog worden uitgevoerd gebruik makend van bijhorend connection object In voorbeeld definieren we een variabele dr van type datareader, die gebruikt wordt om een verwijzing te bevatten naar het datareader object geretourneert door executereader methode. Eenmaal aangemaakty kan je de gegevens doorlopen gebruik makend van Read methode. Haalt rijen 1 per 1 op. Een neveneffect is dat de huidige recordpointer verplaatst wordt naar volgend record.De default positie van de datareader is voor het eerste record. Dus voor het lezen van het eerste record moet je de Read methode reeds aanroepen. Na het beeindigen van het lezen moet je de close methode aanroepen. Noteer dat terwijl je de dataReader gebruikt de geassocieerde connectie records aan het sturen is naar de DataReader. Zolang dit plaatsvindt, kan geen enkel ander SQL statement via dit connection object worden uitgevoerd. De connectie blijft busy tot de Close methode wordt aangeroepen. Dus voer de close zo snel mogelijk uit Visual Basic.NET
27
De DataReader Ophalen van gegevens uit DataReader
Via de collectie van Get methodes (meest performant) GetString, GetInt16, GetInt32, GetDateTime,... Get methodes hebben 1 parameter : volgnr van veld Bevat ook een IsNull methode (true als veld NULL bevat) Do While oDR.Read MessageBox.Show(oDR.GetInt32(0) & “ “ & oDR.GetString(1)) Loop Via de Item property Array (via index of naam veld) MessageBox.Show(cint(oDR(“categoryid”)) & “ “ & oDR(“categoryName”)) Vermits je waarschijnlijk de datatypes van de geretourneerde data kent, kan je de get methodes gebruiken om data in een kolom op te halen in functie van hun data type. Deze benadering verbetert de performantie daar je geen type conversie meer moet doen, maar je data en output moeten identiek zijn! Als je DataReader meerdere resultaatsetten retourneert (bvb Create procedure multiresult as Select * from authors Select * from titles Return 0 GO Do do while odr.read .... loop Loop while odr.nextresult Visual Basic.NET
28
De DataReader Voorbeeld Product Information - revised
DataReader kan je niet binden aan een listbox. Hoe moet je op basis van de productnaam productgegevens terugvinden, indien productnaam niet uniek? Oplossing : Maak een generische klasse ListItem Klik Project > Add Class Geef naam clsItemLists.vb Geef code in Gebruik die klasse in de listLoad procedure Als je het resultaat wenst te plaatsen in een DatAReader object gebruik je de executeReader methode. Het is ook altijd goed om het command type mee te geven. Als je weet dat de uitvoering van je SQL Query geen rijen retourneert moet je ExecuteNonQuery gebruiken Visual Basic.NET
29
Public Class clsItemList Private mValue As String ‘bevat de text
Private mID As Integer ‘bevat de primaire sleutel Public Sub New(ByVal strValue As String,ByVal intID As Integer) mValue = strValue mID = intID End Sub Property Value() As String Get Return mValue End Get Set(ByVal Value As String) mValue = Value End Set End Property Property ID() As Integer Return mID Set(ByVal Value As Integer) mID = Value Public Overrides Function ToString() As String ‘opgeroepen door listbox voor tonen van waarde object End Function End Class Te gebruiken voor elke tabel die je in een listbox plaatst. Elke klasse waarvan je objecten in een listbox wenst te plaatsen moet een ToString methode hebben. Tostring is methode van Object klasse waarvan alle klassen erven. Wanneer een listbox items toont uit zijn items collectie gebruikt hij altijd de toString methode om de waarde op te halen Visual Basic.NET
30
Dim oDr As OleDbDataReader Dim oItem as clsItemList
Private Sub ListLoad() Dim oConn As OleDbConnection() Dim oCmd As OleDbCommand() Dim oDr As OleDbDataReader Dim oItem as clsItemList Dim strSQL as String= “Select ProductID, ProductName from Products order by ProductName” Dim strConn as String= “Provider=... Try oConn = new OleDbConnection(strConn) oCmd = new OleDbCommand(strSQL,oConn) oConn.Open() oDr = oCmd.ExecuteReader() lstProducts.Items.Clear() Do while oDr.Read() oItem = New clsItemList(oDr.Item(“ProductName”).ToString(), cint(oDR.Item(“ProductID”)),) lstProducts.Items.Add(oItem) Loop oDr.Close If lstProducts.Items.Count > 0 then lstproducts.SetSelected(0,True) Catch ex As OleDbException MessageBox.Show(ex.Message) Finally If (Not oConn Is Nothing) AndAlso (oConn.State = ConnectionState.Open) Then oConn.close() End Try End Sub Als je het resultaat wenst te plaatsen in een DatAReader object gebruik je de executeReader methode. Het is ook altijd goed om het command type mee te geven. Als je weet dat de uitvoering van je SQL Query geen rijen retourneert moet je ExecuteNonQuery gebruiken Visual Basic.NET
31
De DataAdapter Brug tussen gegevensbron en DataSet object. SQLDataAdapter OleDbDataAdapter SqlDataAdapter DataSet heeft nooit een live connection met datasource. De DataAdapter connecteert met datasource, voert query uit en geeft resultaat door aan DataSet of voert wijzigingen uit DataSet uit op dataSource Data Provider Connection Object Uitvoeren SQL statement Command Object DataSet DataTables The DataAdapter class acts as a bridge between the connected and disconnected halves of the ADO.NET object model. You can use a DataAdapter to pull data from your database into your DataSet. The DataAdapter can also take the cached updates stored in your DataSet and submit them to your database. The DataAdapter is designed to work with disconnected data. Perhaps the best example of this design is the Fill method. You don't even need a live connection to your database to call the Fill method. If you call the Fill method on a DataAdapter whose connection to your database is not currently open, the DataAdapter opens that connection, queries the database, fetches and stores the results of the query into your DataSet, and then closes the connection to your database. There Is No Direct Connection Between the DataAdapter and the DataSet You fill a DataTable in your DataSet by passing your DataSet as a parameter to the DataAdapter object's Fill method OleDbDataAdapter.Fill(DataSet) Once this call completes, there is no connection between the two objects. The DataSet does not maintain a reference, internally or externally, to the DataAdapter, and the DataAdapter does not maintain a reference to the DataSet. Also, the DataSet contains no information indicating where the data originated—no connection string, no table name, and no column names. Thus, you can pass DataSet objects from your middle-tier server to your client applications without divulging any information about the location or structure of your database. DataAdapter Object Visual Basic.NET
32
De DataAdapter Ophalen van data -> vullen van een dataset
Fill : voert select statement uit en slaat resultaat op in DataTable in DataSet Update : voert wijzigingen in DataTable in DataSet door in database Je hebt geen open connectie nodig. De Fill/update methode opent de connectie, manipuleert data en sluit de connectie Creatie DataAdapter Dim strConn As String strConn = “Provider=Microsoft.Jet.OLEDB.4.0;” strConn &= “Data Source =“ & Application.StartUpPath & “\northwind.mdb” Dim oConn As New OleDbConnection(strConn) Dim oCmd As New OleDbCommand(“Select * from Customers”, oConn) oDA = New oleDbDataAdapter() oDA.SelectCommand = oCmd of verkort via DataAdapter Constructor Dim strConn As String = “Provider=Microsoft.Jet.OLEDB.4.0;Data Source ...” Dim strSQl as String = “Select * from Customers” Dim oDA = New oleDbDataAdapter(strSQl, oConn) Vullen DataSet Using DataAdapter Create Connection, Command and DataAdapter Use DataAdapter.Fill to fill single DataTable Programmatically Construct your own DataSet, DataTable and DataColumns and fill using computated data Read from XML Visual Basic.NET
33
De DataAdapter Vullen van DataSet
Dim oDs as New DataSet() oDA.MissingSchemaAction = MissingSchemaAction.AddWithKey oDa.Fill(oDs,”Customers”) De connectie met de database zal enkel bestaan tijdens de uitvoering van de Fill. Het schema van de DataTable Customers wordt automatisch gegenereerd, en is gebaseerd op de definitie van de tabel in de data source. In DataSet NorthWind wordt tabel gecreëerd met naam Customers (en gemapped met tabel Customer) Vergeet keyword New niet bij DataSet anders krijg je problemen Paging with the DataAdapter object's Fill method You've browsed through product catalogs on line that display items a page at a time. If the catalog has a hundred items, the Web site might display 20 of the items per page. The DataAdapter has a Fill metjod that you can use to fetch only a portion of the results of your query, as shown here: DataAdapter.Fill(DataSet, intStartRecord, intNumRecords, "TableName") Remember that the parameter for the starting record is zero-based. So, the following code snippet fetches the first 20 rows: DataAdapter.Fill(DataSet, 0, 20, "Products") It's also important to keep in mind that using this Fill method affects only which rows are stored in your DataSet. Let's say you're querying a table that contains 1000 rows and you're fetching this data in pages of 20 records each. The following call DataAdapter.Fill(DataSet, 980, 20, "Products") stores the last 20 rows from the query in your DataSet. But the actual query still returns 1000 rows. The DataAdapter simply discards the first 49 pages of data. So, while this Fill method can make it easy to break your query into pages, it's not terribly efficient. There are more efficient (but more complex) ways to achieve paging with DataSet objects and DataReader objects, which we'll discuss in Chapter 14 when I explain how to build efficient Web applications. Opening and Closing Connections In the code snippets that showed how to use the Fill method, you might have noticed a major difference between how the DataAdapter and the Command handle Connection objects. In Chapter 4, before calling one of the Command object's execute methods, we opened the Connection object associated with the Command. Otherwise, the Command would throw an exception. The DataAdapter has no such requirement. If you call a DataAdapter object's Fill method and the SelectCommand property's Connection is closed, the DataAdapter will open the connection, submit the query, fetch the results, and then close the Connection. You might say that the DataAdapter is very tidy. It always returns the SelectCommand property's Connection to its initial state. If you open the Connection before calling the Fill method, the Connection will still be open afterwards. The way the DataAdapter handles Connection objects can come in handy because you're not required to open your Connection. However, there are times when you should write code to open your Connection explicitly. Let's say that as your application starts up, you use multiple DataAdapter objects to populate your DataSet with the results of a few queries. Visual Basic.NET
34
De DataAdapter 1 2 XML 4 3 DataSet 5 Updated XML 6 DataSet
XML Web Services Data Source Client Request data 1 2 SQL query XML 4 Results 3 DataSet 5 Updated XML 6 SQL updates DataSet Visual Basic.NET
35
De DataSet Disconnected verzameling gegevens bijgehouden in de cache.
Bevat een collectie van tabellen, relaties en constraints in XML formaat. Staat altijd los van een gegevensbron Constraints Constraint Columns Column DataSet Tables Table Object Collection Relations Relation Rows Row GEBRUIK : als je in je applicatie wenst te werken met een gedisconnecteerde verzameling gegevens!!! Bijgehouden in de cache van de client computer. Dit object wordt automatisch losgekoppeld van de data source maar bevat nog steeds de moglijkheid om later alle updates aangebracht op de client door te voeren in de data source. Dit object maakt deel uit van de system.data namespace. Er bestaat altijd 1 dataAdapter per datatable in de DataSet Dataset : Je kan een dataset beschouwen als een vereenvoudigde relationele database die bestaat uit tabellen en bijhorende relaties. De tabellen in een dataset kan je manueel creeeren of automatisch door uitvoering van een SQL instructie. De data in een dataset kan geediteerd worden op een gedisconnecteerde manier en de wijzigingen kunnen dan in batch terug naar de database worden gestuurd. Een dataset staat altijd los van een gegevensbron. Een dataset weet niet waar de gegevens vandaan komen en het is zelfs mogelijk dat een dataset gegevens van meerdere bronnen bevat. Een dataset is opgebouwd uit 2 primaire objecten datatableCollection : bevat 0 of meerdere DataTable objecten die op hun beurt bestaan uit 3 verzamelingen : columns, rows en constraints Columns : definieert de kolommen waaruit datatable is opgebouwd : bevat o.a. De eigenschappen columnName, DataType, AllowDBNull(nulls toegelaten), ... Rows : bevat de eigenlijke gegevens zoals gedefinieerd in Columns. Kan leeg zijn. Voor elke rij onderhoudt een DataTable de oorspronkelijke, huidige en voorgestelde waarden. Dit maakt het programmeren een pak eenvoudiger Constraints : ADO.NET ondersteunt 2 constraints : ForeignKeyConstraints en UniqueConstraints. De DataTable bevat zelf een property PrimaryKey DataRelationCollection : bevat 0 of meerdere DataRelations. Zorgt voor een programmatorische interface om van een master rij in een tabel naar de bijhorende rijen in een andere tabel te gaan. Adhv een order stelt een DataRelation je in staat om de bijhorende orderdetails rijen op te halen. A DataTable represents one table of in-memory relational data; the data is local to the .NET-based application in which it resides, but can be populated from a data source such as Microsoft® SQL Server using a DataAdapter The DataTable class is a member of the System.Data namespace within the .NET Framework class library. You can create and use a DataTable independently or as a member of a DataSet, and DataTable objects can also be used in conjunction with other .NET Framework objects including the DataView. You access the collection of tables in a DataSet through the Tables property of the DataSet object. The schema, or structure, of a table is represented by columns and constraints. You define the schema of a DataTable using DataColumn objects as well as ForeignKeyConstraint and UniqueConstraint objects. The columns in a table can map to columns in a data source, contain calculated values from expressions, automatically increment their values, or contain primary key values. In addition to a schema, a DataTable must also have rows in which to contain and order data. The DataRow class represents the actual data contained in a table. You use the DataRow and its properties and methods to retrieve, evaluate, and manipulate the data in a table. As you access and change the data within a row, the DataRow object maintains both its current and original state. You can create parent-child relationships between tables using one or more related columns in the tables. You create a relationship between DataTable objects using a DataRelation. DataRelation objects can then be used to return the related child or parent rows of a particular row. Visual Basic.NET
36
De DataSet Tables : collectie van table objecten
Table : een tabel bestaande uit kolommen, rijen en constraints Je kan meerdere tabellen in 1 dataset laden Dim oConn As New OleDbConnection(strConn) Dim daCustomers, daOrders As OleDbDataAdapter daCustomers = New OleDbDataAdapter("SELECT ... FROM Customers", oConn ) daOrders = New OleDbDataAdapter("SELECT ... FROM Orders", oConn ) Dim ds As New DataSet() daCustomers.Fill(ds) daOrders.Fill(ds) Visual Basic.NET
37
De DataSet Columns : is een collectie van DataColumn objecten
DataColumn : definiëren schema van DataTable Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0; =..." Dim strSQL As String = "SELECT * FROM Customers" Dim oConn As New OleDbConnection(strConn) Dim oDa As New OleDbDataAdapter(strSQL, oConn) Dim oDs As New DataSet() oDa.Fill(oDs, "Customers") Dim oTbl As DataTable = oDs.Tables("Customers") Dim strMsg As String strMsg = "Column information for " & oTbl.TableName & " DataTable" & vbCrLf Dim col As DataColumn For Each col In oTbl.Columns strMsg &= col.ColumnName & " - " & col.DataType.ToString & vbCrLf Next col MessageBox.Show(strMsg) Simply put, DataColumn objects define the schema for your DataTable. When you use the DataAdapter object's Fill method to create a new DataTable, the DataAdapter also creates a DataColumn object for each column in the results of your query. The new DataColumn objects that the DataAdapter creates will have only their most basic properties set—Name, Ordinal, and DataType. Visual Basic.NET
38
De DataSet Rows Collection : alle geretourneerde rijen in DataTable
Index : ophalen van specifieke rij Count : aantal rijen in dataTable Doorlopen van de rijen For each row in oDs.Tables(“Customers”) .... Next DataRow Object : Gegevens van 1 rij in DataTable Via Geparametriseerde item property haal je waarde uit 1 veld op. Voorbeeld 1 Dim strMsg As String Dim oTbl As DataTable = oDs.Tables("Customers") Dim row As DataRow = oTbl.Rows(0) strMsg = "CustomerID = " & row.("CustomerID") & vbCrLf strMsg &= "CompanyNameID = " & row("CompanyName") MessageBox.Show(strMsg) Row.item(“companyid”) of verkort row(“companyid”) infeite werk je nog beter met een index is performanter. Visual Basic.NET
39
De DataSet Voorbeeld 2 : Tonen van de data in Listbox
Doorlopen van rijen Private Sub DisplayCustomers Dim dr as DataRow For each dr in oDS.Tables(“Customers”).Rows lstCustomers.Items.Add(dr(“CustomerName”)) Next End Sub Of via binding lstCustomers.DataSource = oDS.Tables(“Customers”) lstCustomers.DisplayMember = “CustomerName” ‘opgepast hoofdlettergevoelig lstCustomers.ValueMember = “CustomerID” Selecteren van een rij en tonen van detail In SelectedIndexChanged Event van listbox Dim dr as DataRow dr=ds.Tables(“Customers”).Select(“CustomerName=‘” & lstCustomers.SelectedItem & “’”) txtCustomerID.text = dr(0)(“CustomerID”).ToString txtCustomerName.Text = dr(0)(“CustomerName”).ToString Visual Basic.NET
40
De DataSet Toevoegen van een nieuwe DataRow Updaten van een DataRow
Aanpassen inhoud van DataSet (NOG NIET DE DB!!!) Toevoegen van een nieuwe DataRow Dim row As DataRow =oDS.Tables("Customers").NewRow row("CustomerID") = "ALFKI" ... oDS.Tables("Customers").Rows.Add(row) Updaten van een DataRow Dim rowCustomer As DataRow rowCustomer = oDS.Tables("Customers").Rows.Find("ANTON") If rowCustomer Is Nothing Then 'Customer not found! Else rowCustomer.BeginEdit rowCustomer("CompanyName") = "NewCompanyName“ rowCustomer("ContactName") = "NewContactName“ rowCustomer.EndEdit End If Toevoegen To add a row to the table, you assign values to each of the columns. But how does the DataRow determine its structure—which columns it contains? The DataTable object has a NewRow method that returns a new DataRow object that contains information about each of the columns in the table. Once you've created your new DataRow, you can populate the various columns using its Item property. You can also use the Item property to examine the contents of a column in your row. The Item property is the default property of the DataRow object, so you don't even need to explicitly call Item in order to use it. To set the value of a column in a DataRow, you supply the name of the column (or its index or the DataColumn itself) and then assign the desired value. The NewRow method of the DataTable creates a new row, but it does not add that row to the DataTable. Generally speaking, you don't want to add your new row as soon as you've created it because at that point it's empty. The values in the columns are set to the appropriate default values or to Null if they don't have defaults. By creating the new DataRow but not adding it to the Rows collection, you can assign values to your columns before making the new DataRow part of your DataTable. The CustomerID column of our Customers table does not accept Null values but does not have a default value. Say you have a Customers DataTable that has a primary key based on the CustomerID column. If you try to add a new Customers row to the table without assigning a value to the CustomerID column, you'll generate an exception. Once you've supplied values for all the desired columns in your new row and you're ready to add it to the DataTable, you use the Add method of the DataRowCollection and supply your new row Editeren Using BeginEdit and EndEdit is optioneel maar lets you buffer the changes to the row. Calling EndEdit saves the changes to the row. If you decide that you don't want to keep the changes, you can call CancelEdit instead to undo the changes and the row will revert to its state at the time you called BeginEdit. There's another difference tussen het al dan niet gebruiken van BeginEdit. The DataTable has events such as RowChanging, RowChanged, ColumnChanging, and ColumnChanged that you can use to examine the changes to a row or column. When, or if, these events fire depends on how you modify a row—with or without calling BeginEdit and EndEdit. Alj je geen BeginEdit gebruikt, the contents of the row changed each time we modified a column in the row. The DataTable object's events fire each time you modify the contents of a column. Using BeginEdit blocks the events from occurring until you call EndEdit. (If you call CancelEdit instead of EndEdit, the buffered changes will be discarded, and because the row is not updated, the events will not fire.) Visual Basic.NET
41
De DataSet Verwijderen van een rij Null waarden
Dim rowCustomer As DataRow rowCustomer = oDS.Tables("Customers").Rows.Find("ALFKI") oDS.Tables("Customers").Delete Null waarden Testen of een kolom Null waarde bevat rowCustomer = ds.Tables("Customers").Rows.Find("ALFKI") If IsDBNull(rowCustomer("Phone")) Then Console.WriteLine("It's Null") ‘Of If rowCustomer.IsNull(“Phone”) then .... Instellen van een Null waarde rowCustomer("Phone") = DBNull.Value Verwijderen Deleting a row is simpler than modifying one. You simply call the Delete method on the DataRow. However, deleting the row does not remove it from the DataTable. Instead, ADO.NET marks the row as a pending deletion. Why doesn't ADO.NET just remove the DataRow from the table? Remember that the data storage objects in the ADO.NET object model act as a data cache so that you can retrieve data from your database, modify that data in a disconnected mode, and later submit the pending changes. When you call the Delete method on the DataRow, you're not deleting the corresponding row in your database. Instead, you're marking the row as a pending deletion so that you can later submit that pending change to the database. If you completely remove the row from your DataTable, you will not delete the corresponding row in your database when you submit the pending changes stored in your DataSet or DataTable. Null The DataRow object has an IsNull method that you can use to check whether a column contains a Null value. Like the DataRow object's Item method, the IsNull method accepts a column name, an integer that represents the index for the column, or a DataColumn object. When you want to set the value of a column to Null, don't use the Null keyword from your programming language of choice. The .NET Framework includes a class in the System namespace called DBNull. To set the value of a column in a DataRow to Null, use the Value property of the DBNull class Visual Basic.NET
42
De DataSet Via Command objecten Via DataAdapter
Updaten van de DataSource Via Command objecten Via DataAdapter Generatie van update statements .NET genereert de update statements in functie van het SELECT statement dmv CommandBuilder Voorwaarde : Select statement moet primary key bevatten Werkt met optimistische locking Voorbeeld Dim strConn As String = “Provider=Microsoft.Jet.OLEDB.4.0;...” Dim oConn As New OleDbConnection(strConn) Dim strSQl as String = “Select * from Customers” Dim oDA = New oleDbDataAdapter(strSQl, oConn) Dim oCB As New OleDbCommandBuilder(oDA) Je codeert zelf de Update statements (is performanter), nl InsertCommand, UpdateCommand en DeleteCommand Submitten van de updates oDA.Update(oDS, “Customers”) ‘dataset en source table Console.WriteLine(oCB.GetInsertCommand.CommandText) toont het gegenereerde insert commando Update alleen is voldoende als het om 1 enkele tabel gaat die niet gerelateerd is aan andere tabellen. Als ik bvb een products tabel in een dataset plaats en dan in dataset een product delete, dan zal ik als ik de delete ook in de database wens door te voeren een fout krijgen : nl kan product niet deleten omdat er nog orderdetails bestaan voor dit product. In dat geval moet je na de update controleren of alle gelukt is. Optimistische locking controleert of de original waarden van de te verwerken Datarow nog overeenkomen met de waarden die op dat moment in de database staan. Indien dat het geval is wordt de wijziging doorgevoerd, de currentvalue van de DataRow wordt naar de originam value gekopieerd en de rowstate wordt op unchanged gezet. In het andere geval wordt een DbConcurrencyException gethrowed. Dit gedrag wordt veroorzaakt door de defaultwaarde false van de ContinueUpdateOnError property. Dan wordt gestaakt met de update van de db van zodra zich een fout voordoet. Door deze waarde voor de aanroep van de update op true te zetten, wordt na error nog verder gegaan met het updaten van de overige rijen in de dataset. Dit betekent dat de dataset dan ten dele unchanged rijen zal bevatten voor alle gelukte updates, maar de rowstate blijft staan voor alle foutieve rijen, die nog steeds hun originam en current values bevatten van voor de update operatie. The logic that the CommandBuilder uses to generate UPDATE, INSERT, and DELETE queries isn't terribly complex. Like the ADO cursor engine, the CommandBuilder queries the database to determine base table and column names as well as key information for the results of your query. The CommandBuilder can generate updating logic if all of the following are true: Your query returns data from only one table. That table has a primary key. The primary key is included in the results of your query. As we discussed earlier, the primary key ensures that the query-based updates that the CommandBuilder generates can update one row at most. Why does the CommandBuilder place a restriction on the number of tables referenced in the results of your query? We'll discuss this later in the chapter. The CommandBuilder object uses the DataAdapter object's SelectCommand to fetch the metadata necessary for the updating logic. Actually, we discussed this feature briefly in Chapter 4. The Command object's ExecuteReader allows you to request this type of metadata with the results of your query. The following code snippet demonstrates this feature: Visual Basic.NET
43
De DataSet Hoe gebeurt de update? Elke rij bevat verschillende versies
Original : bevat de aanvankelijk in de rij geladen gegevens Default : bevat de standaardwaarden voor de rij (bepaald door de eigenschap DefaultValue van de kolommen). Als er geen defaultwaarden zijn gespecifieerd bevat deze versie dezelfde gegevens als de Original. Current : bevat de bijgewerkte gegevens voor alle kolommen die zijn bijgewerkt en de gegevens uit de versie Original voor de kolommen die niet zijn bijgewerkt Proposed : Nadat BeginEdit is aangeroepen voor een rij en voordat EndEdit opf CancelEdit worden aangeroepen. Als CancelEdit wordt aangeroepen , wordt de versie proposed verwijderd. EndEdit past de versie Proposed toe op de Current Van elke rij zijn steeds de Original en Proposed beschikbaar. De Proposed is enkel voorhanden voor rijen in edit mode of detached datarows Via de indexproperty kan je de waarden van een bepaalde versie uitlezen. Visual Basic.NET
44
De DataSet Elke rij bevat een rijstatus. Property RowState
Added : rij toegevoegd aan de tabel voordat AcceptChanges wordt aangeroepen. Als AcceptChanges werd aangeroepen wordt rowstate ingeteld op Unchanged Deleted : rij waarvoor methode Delete werd aangeroepen Detached : een nieuwe rij die nog niet is toegevoegd aan de DataRowCollection (NewRow) of nog een rij die werd verwijderd uit een DataRowCollection (via Remove) maar nog niet werd gewist. Modified : rij waarvan de gegevens werden verwijderd, maar waarvoor de methode AcceptChanges nog niet is aangeroepen Unchanged : rij waarvoor de gegevens niet zijn gewijzigd sinds AcceptChanges voor het laatst werd aangeroepen. Je zal zelden met detached datarows werken. Visual Basic.NET
45
De DataSet Met de versie en status van een DataRow bevat een DataSet voldoende informatie om de gemaakte mutaties te laten persisteren in een database. De dataAdapter maakt gebruikt van de 3 Command objecten om voor een bepaalde DataRow de overeenkomstige operatie uit te voeren op db. Stuur enkel de gewijzigde rijen naar de database Dim gewijzigdeDs as DataSet If ds.HasChanges then gewijzigdeDs = ds.GetChanges() Dim oCB as New OleDbCommandBuilder(oDa) Da.ContinueUpdateOnError = true Da.Update(dswijzigingen,”Customers”) Voeg originele dataset samen met de ververste wijzigingen Ds.Merge(dsWijzigingen, true) Controleer op errors If ds.HasErrors Dim row as DataRow For each row in ds.GetErrors() Console.writeline(“fout bij updaten “ & row.rowerror & “ voor “ & row(“customerid”) & “ “ & row(“companyname”,DataRowVersion.Current) & “ “ & row(“companyname”, DataRowVersion.Original”) Next Getchanges : maakt een kopie van de dataset met daarin enkel de rijen die een rowstate hebben verschillend van Unchanged en Detached. Deze meestal kleinere dataset kan worden teruggestuurd naar de datalaag?. Een bijkomend voordeel is dat de oorspronkelijke dataset onaangetast blijft waarvan je later dankbaar gebruik kan maken. Een andere manier om op fouten te testen : op basis van events fired door DataAdapter (nog eens verder bekijken) RowUpdating and RowUpdated Events Fired for each DataRow that has changes RowUpdated Event Fires after the execution of the SQL Statement The event Arguments can be used to decide what to do in case of errors RecordsAffect = 0 -> in case of a concurrency violation Status = SkipCurrentRow -> continue updating other rows Errors -> Contains error messages that are generated RowUpdating Event Fires before the execution of the SQL Statement Can be used to customize the actual SQL Statement Visual Basic.NET
46
DataSet Je kan wijzigingen in gegevens in dataset accepteren of annuleren of opnieuw proberen te updaten. Ds.RejectChanges Ds.AcceptChanges Refreshen van data in de DataSet De dataTable moet een primary key bevatten Indien niet, zal de refresh de records die van de database komen acteraan toevoegen 2 manieren om primary key in te stellen Set DataAdapter.MissingSchema = AddWithKey => Eenvoudig, geen codering, PK komt van database Manueel toevoegen aan DataTable => betere performantieBetter performance Voer de DataAdapter.Fill terug uit De bestaande records zullen worden upgedate Als je de bestaande wijzigingen in je Dataset wenst te behouden Vull een nieuwe DataSet Merge wijzigingen en zet PreserveChanges = true Errorhandling met de DataAdapter (nog eens bekijken) ContinueUpdateOnError -Controls Update behavior in case of errors -Default is false -When set to false and errors occur during Update -Exceptions are throw, Update command stops -When set to true and errors occur during Update -No exceptions are thrown -Update command continues processing on next rows -Error information is placed in RowError property of DataRow -DataTable.HasErrors is set to true Nuttige internetadressen • • • • Visual Basic.NET
47
De DataSet Visual Basic.NET
48
De DataSet Demo + bespreking van de code Visual Basic.NET
49
Boeken en info en-us/dndotnet/html/usingadonet.asp Testen bij dataadapter.update methode om weer te geven welke fout zich heeft voorgedaan 'Catch ex As OleDbException ' MessageBox.Show("Update to database failed. Error : " & ex.Message & vbCrLf & "Changes will be lost.") 'Als je de rij met foutmelding wenst weer te geven 'Dim rowsinError As DataRow() 'rowsinError = theproductsiterator.Products.Tables(0).GetErrors 'If rowsinError.Length > 0 Then ' Dim row As DataRow ' Dim strmessage As String ' For Each row In rowsinError ' If row.RowState = DataRowState.Deleted Then ' strmessage &= "Product " & row.Item("productname", DataRowVersion.Original) & " cannot be deleted. " & row.RowError & vbCrLf ' ElseIf row.RowState = DataRowState.Added Then ' strmessage &= "Product " & row.Item("productname", DataRowVersion.Original) & " cannot be added. " & row.RowError & vbCrLf ' ElseIf row.RowState = DataRowState.Modified Then ' strmessage &= "Product " & row.Item("productname", DataRowVersion.Original) & " cannot be modified. " & row.RowError & vbCrLf ' End If ' Next ' MessageBox.Show(strmessage) 'End If 'End Try Visual Basic.NET
50
Programming guidelines
DataReader or DataSet DataSet supports caching and serialization DataReader has best performance DataReader is use-once object Comparable to SAX or DOM Managed provider to use ODBC: for old ODBC drivers OLE DB: for general OLEDB connections SQL Server: for SQL Server only connections Visual Basic.NET
51
De DataReader Zoeken van waarden in een comboBox
Pas Load event Form aan Codeer de procedures SupplierLoad en CategoryLoad Private Sub frmProduct_Load( ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' Load Suppliers SupplierLoad() ' Load Categories CategoryLoad() ' Load List Box of Products ListLoad() End Sub Visual Basic.NET
52
En verder Performantie opdrijven door Stored procedures
Zelf InsertCommand, UpdateCommand, DeleteCommand te creëeren en niet te werken met CommandBuilder Typed DataSets (XML) -> Maar dit behoort tot de leerstof van volgend jaar. Visual Basic.NET
53
Database Interactions Are Performed Using Data Commands
To perform operations in a database, you execute SQL statements or stored procedures (which include SQL statements). You use SQL statements or stored procedures to read and write rows and perform aggregate functions, such as adding or averaging. You also use SQL statements or stored procedures to create or modify tables or columns, to perform transactions, and so on. In ADO.NET you use data commands to package a SQL statement or stored procedure. For example, if you want to read a set of rows from the database, you create a data command and configure it with the text of a SQL Select statement or the name of a stored procedure that fetches records. When you want to get the rows, you do the following: Open a connection. Call an execute method of the command, which in turn: Executes the SQL statement or stored procedure referenced by the command. Then closes the connection. The connection stays open only long enough to execute the statement or stored procedure. When you call a command's execute method, it returns a value. Commands that update the database return the number of rows affected; other types of commands return an error code. If the command queries the database with a SELECT statement, the command can return a set of rows. You can fetch these rows using a data reader, which acts as a very fast read-only, forward-only cursor. If you need to perform more than one operation — for example, read some rows and then update them — you use multiple data commands, one for each operation. Each operation is performed separately. For example, to read the rows, you open the connection, read the rows, and then close the connection. When you want to update data, you again open the connection, perform the update, and then close the connection again. Data commands can include parameters (specifically, a collection of parameter objects) that allow you to create parameterized queries such as the following: Select * From customers Where (customer_id You can then set the parameters at run time and execute the command to return or update the data you want. Data Can Be Cached in Datasets The most common data task is to retrieve data from the database and do something with it: display it, process it, or send it to another component. Very frequently, the application needs to process not just one record, but a set of them: a list of customers or today's orders, for example. Often the set of records that the application requires comes from more than one table: my customers and all their orders; all authors named "Smith" and the books they have written; and other, similar, sets of related records. Once these records are fetched, the application typically works with them as a group. For example, the application might allow the user to browse through all the authors named "Smith" and examine the books for one Smith, then move to the next Smith, and so on. In many cases, it is impractical to go back to the database each time the application needs to process the next record. (Doing so can undo much of the advantage of minimizing the need for open connections.) A solution, therefore, is to temporarily store the records retrieved from the database and work with this temporary set. This is what a dataset is. A dataset is a cache of records retrieved from a data source. It works like a virtual data store: A dataset includes one or more tables based on the tables in the actual database, and it can include information about the relationships between those tables and constraints on what data the tables can contain. The data in the dataset is usually a much-reduced version of what is in the database. However, you can work with it in much the same way you do the real data. While you are doing so, you remain disconnected from the database, which frees it to perform other tasks. Of course, you often need to update data in the database (although not nearly as often as you retrieve data from it). You can perform update operations on the dataset, and these can be written through to the underlying database. An important point is that the dataset is a passive container for the data. To actually fetch data from the database and (optionally) write it back, you use data adapters. A data adapter contains one or more data commands used to populate a single table in the dataset and update the corresponding table in the database. (A data adapter typically contains four commands, one each to select, insert, update, and delete rows in the database.) Therefore, a data adapter's Fill method might execute a SQL statement such as SELECT au_id, au_lname, au_fname FROM authors whenever the method is called. Because a dataset is effectively a private copy of the database data, it does not necessarily reflect the current state of the database. If you want to see the latest changes made by other users, you can refresh the dataset by calling the appropriate Fill method. One of the advantages of using datasets is that components can exchange them as required. For example, a business object in the middle tier might create and populate a dataset, then send it to another component elsewhere in the application for processing. This facility means that components do not have to individually query the database. Datasets Are Independent of Data Sources Although a dataset acts as a cache for data drawn from a database, the dataset has no actual relationship with the database. The dataset is a container; it is filled by SQL commands or stored procedures executed from a data adapter. Because a dataset is not directly tied to a data source, it is a good integration point for data coming from multiple sources. For example, some of the data in a dataset might come from your database, whereas other parts of it might come from a different database or a non-database source such as a spreadsheet. Some of the data in a dataset might arrive in a stream sent by another component. Once the data is in a dataset, you can work with it using a consistent object model, regardless of its original source. Data Is Persisted as XML Data needs to be moved from the data store to the dataset, and from there to various components. In ADO.NET the format for transferring data is XML. Similarly, if data needs to be persisted (for example, into a file), it is stored as XML. If you have an XML file, you can use it like any data source and create a dataset out of it. In fact, in ADO.NET, XML is a fundamental format for data. The ADO.NET data APIs automatically create XML files or streams out of information in the dataset and send them to another component. The second component can invoke similar APIs to read the XML back into a dataset. (The data is not stored in the dataset as XML — for example, you cannot parse data in a dataset using an XML parser — but instead in a more efficient format.) Basing data protocols around XML offers a number of advantages: XML is an industry-standard format. This means that your application's data components can exchange data with any other component in any other application, as long as that component understands XML. Many applications are being written to understand XML, which provides an unprecedented level of exchange between disparate applications. XML is text-based. The XML representation of data uses no binary information, which allows it to be sent via any protocol, such as HTTP. Most firewalls block binary information, but by formatting information in XML, components can still easily exchange the information. For most scenarios, you do not need to know XML in order to use data in ADO.NET. ADO.NET automatically converts data into and out of XML as needed; you interact with the data using ordinary programming methods. Schemas Define Data Structures Although you do not need to know anything about XML to read and write to the database and work with datasets, there are situations in which working with XML is precisely the goal you are after. These are situations in which you are not accessing data, but instead, working with the design of data. To put it another way, in ADO.NET you use XML directly when you are working with metadata. Datasets are represented as XML. The structure of the dataset — the definition of what tables, columns, data types, constraints, and so on are in the dataset — is defined using an XML Schema based on the XML Schema definition language (XSD). Just as data contained by a dataset can loaded from and serialized as XML, the structure of the dataset can be loaded from and serialized as XML Schema. For most of the work you do with data in ADO.NET, you do not have to delve deeply into schemas. Typically, the Visual Studio .NET tools will generate and update schemas as needed, based on what you do in visual designers. For example, when you use the tools to create a dataset representing tables in your database, Visual Studio .NET generates an XML Schema describing the structure of the dataset. The XML Schema is then used to generate a typed dataset, in which data elements (tables, columns, and so on) are available as first-class member.However, there are times when you want to create or edit schemas yourself. A typical example is developing a schema in conjunction with a partner or client. In that case, the schema serves as a contract between you and the partner regarding the shape of the XML-based data you will exchange. In that situation, you will often have to map the schema elements to the structure of your own database. For more information about designing schemas, see XML Schemas and Data. Visual Basic.NET
54
Uitvoeren van SQL instructie
Voorbeeld 1 : SQL Tester Maak nieuwe Windows Applicatie met naam SQLTester Creëer form Visual Basic.NET
55
Uitvoeren van SQL instructie
Dubbelklik Connect knop en schrijf volgende code Opm : sluit altijd de connectie af. Wacht niet tot object out of scope gaat. Close geeft de connectie terug aan de pool, zodat de connectie kan herbruikt worden door een andere procedure Private Sub btnConnect_Click( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.Click Dim oConn As OleDbConnection Dim strConn As String Try oConn = New OleDbConnection() strConn = “Provider=Microsoft.Jet.OLEDB.4.0;” strConn &= “Data Source =“ & Application.StartUpPath & “\northwind.mdb” oConn.ConnectionString = strConn oConn.Open() MessageBox.Show("Connection Open", "btnConnect_Click()") oConn.Close() ‘close the connection Catch oExcept As Exception MessageBox.Show(oExcept.Message, "btnConnect_Click()") End Try End Sub Visual Basic.NET
56
Uitvoeren van SQL instructie
Dubbelklik Execute knop en schrijf volgende code Private Sub btnExecute_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnExecute.Click Dim oCmd As OleDbCommand Dim strConn As String Try strConn = “Provider=Microsoft.Jet.OLEDB.4.0;” strConn &= “Data Source =“ & Application.StartUpPath & “\northwind.mdb” oCmd = New OleDbCommand() oCmd.Connection = New OleDbConnection(strConn) oCmd.Connection.Open() oCmd.CommandText = txtSQL.Text ' Assign the SQL to the Command Object ' Execute the SQL, Return Number of Records Affected txtRows.Text = oCmd.ExecuteNonQuery().ToString() MessageBox.Show("SQL statement succeeded", "btnExecute_Click()") oCmd.Connection.Close() Catch oExcept As Exception txtRows.Text = 0.ToString() MessageBox.Show("Error executing SQL: " & oExcept.Message, "btnExecute_Click()") End Try End Sub Visual Basic.NET
57
Uitvoeren van SQL instructie
Opmerking : Maak een ConnectionStringBuild functie Private Function ConnectStringBuild() As String Dim strConn As String strConn &= “Provider=Microsoft.Jet.OLEDB.4.0;” strConn &= “Data Source =“ & Application.StartUpPath & “\northwind.mdb” Return strConn End Function Visual Basic.NET
58
De DataReader Voorbeeld Product Information - revised
DataReader kan je niet binden aan een listbox. Hoe moet je op basis van de productnaam productgegevens terugvinden, indien productnaam niet uniek? Oplossing : Maak een generische klasse ListItem Klik Project > Add Class Geef naam clsItemLists.vb Geef code in Gebruik die klasse in de listLoad procedure Als je het resultaat wenst te plaatsen in een DatAReader object gebruik je de executeReader methode. Het is ook altijd goed om het command type mee te geven. Als je weet dat de uitvoering van je SQL Query geen rijen retourneert moet je ExecuteNonQuery gebruiken Visual Basic.NET
59
Public Class clsItemList Private mValue As String ‘bevat de text
Private mID As Integer ‘bevat de primaire sleutel Public Sub New(ByVal strValue As String,ByVal intID As Integer) mValue = strValue mID = intID End Sub Property Value() As String Get Return mValue End Get Set(ByVal Value As String) mValue = Value End Set End Property Property ID() As Integer Return mID Set(ByVal Value As Integer) mID = Value Public Overrides Function ToString() As String ‘opgeroepen door listbox voor tonen van waarde object End Function End Class Te gebruiken voor elke tabel die je in een listbox plaatst. Elke klasse waarvan je objecten in een listbox wenst te plaatsen moet een ToString methode hebben. Tostring is methode van Object klasse waarvan alle klassen erven. Wanneer een listbox items toont uit zijn items collectie gebruikt hij altijd de toString methode om de waarde op te halen Visual Basic.NET
60
Dim oDr As OleDbDataReader Dim oItem as clsItemList
Private Sub ListLoad() Dim oCmd As OleDbCommand() Dim oDr As OleDbDataReader Dim oItem as clsItemList Dim strSQL as String Dim strConn as Strings= ConnectStringBuild() strSQL = “Select ProductID, ProductName from Products order by ProductName” Try oCmd = new OleDbCommand() With oCmd .Connection = New OleDbConnection(strConn) .Connection.Open() .CommandText = strSQL oDr = .ExecuteReader() End With lstProducts.Items.Clear() Do while oDr.Read() oItem = New clsItemList(oDr.Item(“ProductName”).ToString(), cint(oDR.Item(“ProductID”)),) lstProducts.Items.Add(oItem) Loop If lstProducts.Items.Count > 0 then lstproducts.SetSelected(0,True) Catch ex As OleDbException MessageBox.Show(ex.Message) End Try End Sub Als je het resultaat wenst te plaatsen in een DatAReader object gebruik je de executeReader methode. Het is ook altijd goed om het command type mee te geven. Als je weet dat de uitvoering van je SQL Query geen rijen retourneert moet je ExecuteNonQuery gebruiken Visual Basic.NET
61
De DataReader Tonen van de Product Detail informatie
Dubbelklik lstProducts en voeg code toe Voeg procedure ShowDetail toe Opmerkingen Ctype : converteert van 1 data type naar een ander Converteert een object type in een clsItemList type Private Sub lstProducts_SelectedIndexChanged( _ ByVal sender As Object, ByVal e As System.EventArgs) _ Handles lstProducts.SelectedIndexChanged ShowDetail() End Sub Visual Basic.NET
62
De DataReader Private Sub ShowDetail() Dim oCmd As OleDbCommand
Dim oDR As OleDbDataReader Dim oItem As clsItemList Dim strSQL As String Dim strConn As String strConn = ConnectStringBuild() oItem = CType(lstProducts.SelectedItem, clsItemList) ' Get Primary Key From List Box strSQL = "SELECT ProductID, ProductName, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued " strSQL &= " FROM Products " strSQL &= " WHERE ProductID = " & oItem.ID Try oCmd = New OleDbCommand() With oCmd .Connection = New OleDbConnection(strConn) .Connection.Open() .CommandText = strSQL oDR = .ExecuteReader() End With Als je het resultaat wenst te plaatsen in een DatAReader object gebruik je de executeReader methode. Het is ook altijd goed om het command type mee te geven. Als je weet dat de uitvoering van je SQL Query geen rijen retourneert moet je ExecuteNonQuery gebruiken Visual Basic.NET
63
De DataReader If oDR.Read() Then With oDR
txtID.Text = .Item("ProductID").ToString() txtName.Text =.Item("ProductName").ToString() txtQty.Text = .Item("QuantityPerUnit").ToString() txtPrice.Text = .Item("UnitPrice").ToString() txtInStock.Text = .Item("UnitsInStock").ToString() txtOnOrder.Text = .Item("UnitsOnOrder").ToString() txtReorder.Text = .Item("ReorderLevel").ToString() chkDisc.Checked = CType(.Item("Discontinued"), Boolean) End With End If oDR.Close() oCmd.Connection.Close() Catch oException As Exception MessageBox.Show(oException.Message) End Try End Sub Als je het resultaat wenst te plaatsen in een DatAReader object gebruik je de executeReader methode. Het is ook altijd goed om het command type mee te geven. Als je weet dat de uitvoering van je SQL Query geen rijen retourneert moet je ExecuteNonQuery gebruiken Visual Basic.NET
64
De DataReader Vullen van de comboboxen Supplier en Category
Pas Load event Form aan Codeer de procedures SupplierLoad en CategoryLoad Private Sub frmProduct_Load( ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' Load Suppliers SupplierLoad() ' Load Categories CategoryLoad() ' Load List Box of Products ListLoad() End Sub Visual Basic.NET
65
De DataReader Private Sub CategoryLoad() Dim oCmd As OleDbCommand
Dim oDR As OleDbDataReader Dim oItem As clsItemList Dim strSQL As String Dim strConn As String strConn = ConnectStringBuild() strSQL = "SELECT CategoryID, CategoryName FROM Categories" Try oCmd = New OleDbCommand() With oCmd .Connection = New OleDbConnection(strConn) .Connection.Open() .CommandText = strSQL ' Closes connection when closing DataReader object oDR = .ExecuteReader(CommandBehavior.CloseConnection) End With Visual Basic.NET
66
De DataReader Do While oDR.Read()
oItem = New clsItemList(oDR.Item("CategoryName").ToString(), CInt(oDR.Item("CategoryID"))) cboCategory.Items.Add(oItem) Loop oDR.Close() ' No need to close this because of the CloseConnection on the ExecuteReader 'oCmd.Connection.Close() Catch oExcept As Exception MessageBox.Show(oExcept.Message) End Try End Sub Visual Basic.NET
67
De DataReader Updaten van een rij Private Sub DataUpdate()
Dim oCmd As OleDbCommand Dim strSQL As String Dim intRows As Integer strSQL = "UPDATE Products SET " strSQL &= "ProductName = " & Str2Field(txtName.Text) & ", " strSQL &= "SupplierID = " & CType(cboSupplier.Items(cboSupplier.SelectedIndex), clsItemList).ID & ", " strSQL &= "CategoryID = " & CType(cboCategory.Items(cboCategory.SelectedIndex), clsItemList).ID & ", " strSQL &= "QuantityPerUnit = " & Str2Field(cboSupplier.Text) & ", " strSQL &= "UnitPrice = " & txtPrice.Text & ", " strSQL &= "UnitsInStock = " & txtInStock.Text & ", " strSQL &= "UnitsOnOrder = " & txtOnOrder.Text & ", " strSQL &= "ReorderLevel = " & txtReorder.Text & ", " strSQL &= "Discontinued = " & CType(IIf(chkDisc.Checked, "1", "0"), String) strSQL &= " WHERE ProductID = " & CType(lstProducts.SelectedItem, clsItemList).ID Visual Basic.NET
68
De DataReader Try oCmd = New OleDbCommand() With oCmd
.Connection = New OleDbConnection(ConnectStringBuild()) .Connection.Open() .CommandText = strSQL intRows = .ExecuteNonQuery() If intRows <> 1 Then MessageBox.Show("Did not insert row") .Connection.Close() End With Catch oException As Exception MessageBox.Show(oException.Message) End Try End Sub Visual Basic.NET
69
De DataReader String velden moeten tussen ‘ staan
Private Function Str2Field(ByVal strValue As String) As String If strValue.Trim() = "" Then Return "Null" Else Return "'" & strValue.Trim() & "'" End If End Function Visual Basic.NET
70
De DataReader Toevoegen van een rij Private Sub DataInsert()
Dim oCmd As OleDbCommand Dim strSQL As String Dim intRows As Integer strSQL = “INSERT INTO Products VALUES(" strSQL &= Str2Field(txtName.Text) & ", " strSQL &= CType(cboSupplier.Items(cboSupplier.SelectedIndex), clsItemList).ID & ", " strSQL &= CType(cboCategory.Items(cboCategory.SelectedIndex), clsItemList).ID & ", " strSQL &= Str2Field(cboSupplier.Text) & ", " strSQL &= txtPrice.Text & ", " strSQL &= txtInStock.Text & ", " strSQL &= txtOnOrder.Text & ", " strSQL &= txtReorder.Text & ", " strSQL &= CType(IIf(chkDisc.Checked, "1", "0"), String) Visual Basic.NET
71
De DataReader Schrappen van een rij Private Sub DataDelete()
Dim oCmd As OleDbCommand Dim strSQL As String Dim intRows As Integer strSQL = “DELETE FROM Products " strSQL &= " WHERE ProductID = " & CType(lstProducts.SelectedItem, clsItemList).ID Visual Basic.NET
72
De DataSet Validatie van rijen in DataSet Getypeerde dataset
Validatie Properties van de DataColumn ReadOnly : kolom kan niet gewijzigd worden AllowDBNull : al dan niet verplicht in te vullen. MaxLength : maximaal aantal characters Unique : kolom mag al dan niet duplicate waarden bevatten. ADO.NET throwt een ConstraintException. The DataTable Object's Constraints Collection UniqueConstraints : kan je ook instellen via DataColumn PrimaryKey ForeignKeyConstraints : kan je ook instellen via Relations Databases offer different mechanisms that you can use to ensure that the data in your database is valid. The sample Northwind database has many rules and constraints defined. The CustomerID column in the Customers table must be populated with a string of up to five characters, and that value must be unique within the table. The Orders table generates a new OrderID value for each row and requires that the CustomerID value for each row refer to an existing entry in the Customers table.Sometimes you'll want to apply similar rules to validate data in your application before submitting changes to your database. For example, let's say you're shopping on line and reach the page where you purchase the items in your basket. Most Web sites will make sure you've entered information into each of the required fields before they submit your order information to the appropriate database. This type of logic might seem redundant because the database probably has similar validation rules defined. However, adding validation rules to your application can improve its performance. The ADO.NET DataSet offers many of the same data validation mechanisms available in database systems. You can separate these validation mechanisms, also called constraints, into two categories—column-level restrictions and table-level restrictions Validation Properties of the DataColumn The DataColumn object exposes a number of properties that you can use to validate your data. ReadOnly The simplest way to ensure that your data is valid is to not let users modify it. If you want to make the data in a DataColumn read-only, set the ReadOnly property of the DataColumn to True. AllowDBNull Some database columns require values, while others accept empty, or null, values. The DataColumn object exposes an AllowDBNull property that you can set to control whether the column in your DataSet accepts null values. MaxLength Many databases place restrictions on the size of a string in a column. In the Customers table, for example, the CustomerID column accepts a string of up to 5 characters and the CompanyName column accepts up to 40 characters. You can place similar restrictions on a DataColumn using the MaxLength property. Unique The DataColumn lets you specify which values in a column are unique using the Unique property. When you set this property to True on a DataColumn, ADO.NET will examine the value stored in this column of each row in your DataTable. If you add or modify a row in your DataTable to create a duplicate value in a unique column, ADO.NET will throw a ConstraintException. The DataTable Object's Constraints Collection You can also validate data in your DataSet by setting properties of the DataTable object. The ADO.NET object model includes two classes that you can use to define constraints in a DataTable. These classes, UniqueConstraint and ForeignKeyConstraint, are derived from the Constraint class. The DataTable exposes a Constraints property that you can use to add to, modify, or examine the constraints on the DataTable. UniqueConstraints If you set the Unique property of a DataColumn to True, you've defined a unique constraint in the DataTable that contains that column. At the same time, you've also added a UniqueConstraint object to the DataTable object's Constraints collection. Setting the Unique property of a DataColumn is simpler than creating a new UniqueConstraint in a DataTable object's Constraints collection. However, there are times when you'll want to explicitly create a UniqueConstraint, such as when you need to make sure that the combinations of values from multiple columns are unique. PrimaryKey A primary key is a special type of unique constraint. The ADO.NET DataRowCollection object has a Find method that you can use to locate a row in your DataTable by the value or values in its primary key column, as shown here. (I'll discuss the Find method in detail in Chapter 8.) row = MyTable.Rows.Find("ALFKI") A DataTable can have multiple unique constraints but can contain at most one primary key. You can set or examine a DataTable object's primary key using its PrimaryKey property. ForeignKeyConstraint You can also add foreign constraints to a DataTable. I described an example of a foreign key constraint just a couple pages back. Each order in the Northwind database's Orders table must have a value for its CustomerID column that is used in the Customers table. You can place similar restrictions on the data in your DataSet by creating a ForeignKeyConstraint and adding it to the table whose rows you want to validate. You generally won't need to explicitly create a ForeignKeyConstraint. Creating a DataRelation between two DataTable objects within your DataSet creates a ForeignKeyConstraint in the process. In the next chapter, I'll discuss the DataRelation object and how you can use it to work with relational data. Note ADO.NET does not know what data resides in your database. Constraints you define on columns and tables within your DataSet are valid only within that DataSet. This is an important point to keep in mind. Here's why. Say you define a UniqueConstraint based on the CustomerID column in your DataTable. If you add a row with a CustomerID of ZZZZZ, ADO.NET will throw an exception only if another row in your DataTable has that same value for the CustomerID column. Foreign key constraints are enforced in a similar fashion. If you define a foreign key on your orders DataTable object based on the CustomerID column in your orders and customers DataTable objects, ADO.NET will let you add only orders with a value for the CustomerID column that appears in your customers DataTable. ADO.NET will throw an exception if you add a new order with a CustomerID that is used in your database but that does not reside in your customers DataTable. Visual Basic.NET
73
Try This at Home, But Only at Home....
De DataSet Instellen van die properties (null, maxlength) via oDA.MissingSchemaAction = MissingSchemaAction.AddWithKey Validating data takes time. In many scenarios, you don't want to set validation properties on your DataSet, so the DataAdapter does not set validation properties on DataColumn objects or add constraints to a DataTable object's Constraints collection when it creates the DataTable in the DataAdapter object's Fill method unless you make an explicit request. There are two ways to tell the DataAdapter that you want to retrieve this schema information from your database when adding columns to your DataTable—by setting the DataAdapter object's MissingSchemaAction property to AddWithKey or by calling the DataAdapter object's FillSchema method. (I covered these features of the DataAdapter in Chapter 5.) Try This at Home, But Only at Home.... ADO.NET has a few features that you should avoid using in your applications whenever possible. Fetching schema information for your DataSet through the DataAdapter is one of them. Using the DataAdapter to gather schema information can save time during the design process. In fact, Visual Studio .NET uses the DataAdapter to generate your DataSet objects at design time (as you'll see later in this chapter). If you're building a small sample or a proof-of-concept application, you might find that using the DataAdapter to gather schema information reduces the amount of code you have to write. But unless your application is an ad-hoc query tool, you should know which columns your queries return, so you should have no need to use features such as DataAdapter.FillSchema in your full-blown applications. If you ask your DataAdapter to fetch additional schema information using these features, the DataAdapter will query your database for schema information beyond the name and data type for each new DataColumn it creates. Examine any of these DataColumn objects and you'll find that the ReadOnly, AllowDBNull, MaxLength, and ReadOnly properties are set correctly. The DataAdapter will also attempt to generate a primary key for your DataTable. This is where you pay a significant performance penalty to fetch schema information. Here's why. The DataAdapter has to query the database to determine which table your query references, and then it has to query the database again to gather information about the primary key for that table. If no primary key is defined for your table, the DataAdapter will request information about unique indexes for the table. Once the DataAdapter has gathered this information about your table, it will examine the columns returned by your query. This ensures that if your table contains a primary key comprising two columns but the query you're using does not include both of these columns, the DataAdapter will not use this primary key in your DataTable. Note The DataAdapter will also set the AutoIncrement property of new DataColumn objects. I'll cover this property briefly later in this chapter. For more in-depth information on using this property, see Chapter 11. Fetching Schema Information The DataTable object, which we'll discuss in detail in the following chapter, is designed to enforce constraints on your data such as a primary key, maximum length of string fields, and nullability constraints. Fetching this information at run time can be costly, and in many cases developers have no need to retrieve this information. So, by default the DataAdapter does not fetch this information. However, if you encounter a situation in which you're willing to pay the performance penalty to retrieve schema information about your results, there are a couple key features of the DataAdapter that you can use: the MissingSchemaAction property and the FillSchema method. (Yes, I know that's an absolutely terrible pun.) The MissingSchemaAction Property You might have noticed that, so far, all of the examples that use the DataAdapter object's Fill method use DataSet objects and DataTable objects that contain no schema information. By default, the DataAdapter will add columns to store the results of your query if those columns do not already exist in your DataSet or DataTable. This behavior is governed by the MissingSchemaAction property. This property accepts values from the MissingSchemaAction enumeration in the System.Data namespace. The default value for this property is Add. As with MissingMappingAction, you can ignore missing columns by setting the property to Ignore or throw an exception in such circumstances by setting the property to Error. There's another value in the MissingSchemaAction enumeration: AddWithKey. The name of this value is slightly misleading. If you set the property to this value and the DataAdapter encounters a column that does not exist in your DataSet or DataTable, the DataAdapter adds the column and sets two additional schema attributes of the property: MaxLength and AllowDBNull. If the DataTable does not yet exist or does not contain any columns, this value also causes the DataAdapter to query the database for primary key information. The FillSchema Method The DataAdapter also has a FillSchema method that you can use to fetch only schema information into your DataSet or DataTable. The FillSchema method's signatures mirror the basic Fill signatures. You can supply a DataSet, a DataTable, or a DataSet and a table name in the FillSchema method. Each FillSchema method also requires a value from the SchemaType attribute: Mapped or Source. The value you specify in this parameter determines whether the DataAdapter will apply the settings in its TableMappings collection to the results of the query. If you call the FillSchema method and use Source as the SchemaType, the DataAdapter will use the column names that the query returns. Using Mapped as the SchemaType will cause the DataAdapter to apply the settings in its TableMappings to the columns returned by the query. FillSchema will set the AutoIncrement, AllowDBNull, and MaxLength properties on the columns returned and will also create a primary key on the resulting DataTable if the database indicates that a column or set of columns represents a primary or unique key. Visual Basic.NET
74
De DataSet Formatteren van velden in gebonden controls
De Add methode retourneert een Binding object dat reageert op CM object events en die data moved tussen textbox en kolom waarmee tekstbox gebonden is. Binding object heeft 2 events : Format en Parse Format event : bij laden van data in textbox Parse event : bij schrijven data in dataSet Visual Basic.NET
75
Handling Identity Columns
Problem: Identity values are only generated upon insert Solution Client values should not conflict with server values Set AutoIncrement Seed and Step to -1 on DataTable When doing the insert in the DB, retrieve the new AutoIncrement value Modify the value in the inserted DataRow with the new one In case of parent-child relations Insert Parent rows before Child rows Use UpdateRule.Cascade on DataRelation between Parent and Child Visual Basic.NET
76
Handling Identity Columns
Solution (continued) How do you retrieve the new Identity value ? Do a “select scope_identity()” after insert statement As an output parameter of a Insert Stored Procedure How do you map the new Identity value to the DataRow? Set DataAdapter.SelectCommand.UpdateRowSource FirstReturnedRecord maps fields of first returned record to inserted DataRow OutputParameter maps output parameters of stored procedure to inserted DataRow Default is Both Visual Basic.NET
77
Handling Identity Columns
Problem: Identity values are only generated upon insert Easier Solution: make your primary key fields of the type UniqueIdentifier (GUID) Can be generated in the client No need to fetch back inserted value Easier to program with Visual Basic.NET
78
Populating Multiple DataTables
Retrieve multiple results in a single call Execute Batch statement or stored procdure Map results to appropriate tables using tablemappings Use ExecuteXmlReader to retrieve hierarchical results Load with ReadXml using XmlReadMode.Fragment Submit updates in batches Sample batch update example available soon… Or save as DiffGram and send to SqlXml Dim adapter As New SqlDataAdapter( _ "SELECT * FROM customers; SELECT * FROM orders",cnn) adapter.TableMappings.Add("Table1","Customer") adapter.TableMappings.Add("Table2","Orders") adapter.Fill(myDataSet) Visual Basic.NET
79
Looking Up Values In The Dataset
Searching for Results within a DataSet DataTable.Find() for searching on PK values DataView.Select() for repeated non-PK queries Sort DataView by search fields DataView builds an index for sorted columns Pass Table, filter, sort, RowState to constructor Dim customer = customerTable.Rows.Find("GROSR") Dim customerView As New DataView(customerTable) customerView.Sort = "State" Dim customers = customerView.FindRows("CA") Dim view As New DataView( _ customerTable, _ "Country=USA", _ "Region", _ DataViewRowState.CurrentRows ) Visual Basic.NET
80
Controlling How The XML Is Generated
DataSet lets you control how XML is generated Name, Namespace properties on DataSet, DataTable, DataColumn MappingType property on DataColumn defines how data is written Element, Attribute, SimpleType, Hidden Nested Property on DataRelation controls how children are written ' Write out CustomerID, OrderID as Attributes ds.Tables("Customers").Columns("CustomerID").ColumnMapping = MappingType.Attribute ds.Tables("Orders").Columns("OrderID").ColumnMapping = MappingType.Attribute ' Write out Orders as children of Customers ds.Relations("cust_orders").Nested = True <?xml version="1.0" standalone="yes"?> <CustomerOrders> <Customers CustomerID="GROSR"> <ContactName>Manuel Pereira</ContactName> <Orders OrderID="10268"> <CustomerID>GROSR</CustomerID> <OrderDate> </OrderDate> </Orders> </Customers> </CustomerOrders> Visual Basic.NET
Verwante presentaties
© 2024 SlidePlayer.nl Inc.
All rights reserved.