Databaser och C# ADO.NET Murach Kapitel 17-20 1 2013-01-30 © Winstrand Development Databas • ADO.NET – Är en del av .NET ramverket och tillhandahåller delar för att kommunicera med olika datakällor. – Dessa kan vara databaser, textfiler, Excelark eller XML-filer. – Vi kommer att inrikta oss på att arbeta mot databaser. © Winstrand Development 2013-01-30 2 Uppgiftslämnare (Data Providers) • Vi vet att ADO.NET låter oss interagera med olika typer av datakällor och olika typer av databaser. Det finns dock inte en enda uppsättning klasser som tillåter dig att uppnå detta universellt. Eftersom olika datakällor använder olika protokoll, behöver vi ett sätt att kommunicera med rätt datakälla genom rätt protokoll. • Vissa äldre datakällor använder ODBC-protokollet, många nyare datakällor använder OLEDB protokollet och det kommer fler datakällor varje dag som tillåter att du kommunicerar direkt med dem genom .NETs ADO.NET klassbibliotek. © Winstrand Development 2013-01-30 3 Data Providers forts. • ADO.NET ger en relativt vanligt sätt att samverka med datakällor, men finns i olika uppsättningar av bibliotek för varje sätt du kan prata med en datakälla. Dessa bibliotek kallas Data Providers. © Winstrand Development 2013-01-30 4 Tabellen listar några välkända uppgiftslämnare, API prefixet de använder, och vilken typ av datakälla de tillåter dig att interagera med. Data källa API Prefix Beskrivning Odbc Data Sources with an ODBC interface. Normally older data bases. OleDb Data Provider OleDb Data Sources that expose an OleDb interface, i.e. Access or Excel. Oracle Data Provider Oracle For Oracle Databases. SQL Data Provider Sql For interacting with Microsoft SQL Server. Bdp Generic access to many databases such as Interbase, SQL Server, IBM DB2, and Oracle. ODBC Data Provider Borland Data Provider © Winstrand Development 2013-01-30 5 ADO.NET Objekt SQLConnection object • För att interagera med en databas måste du ha en anslutning till den. • Anslutningen hjälper till att identifiera databasservern, databasnamn, användarnamn, lösenord och andra parametrar som krävs för att ansluta till databasen. • Ett anslutningsobjekt används av kommandoobjektet så att de vet vilken databas som ska användas. © Winstrand Development 2013-01-30 6 ADO.NET Objekt SqlCommand object • Processen att interagera med en databas innebär att du måste ange de åtgärder du vill ska inträffa. • Detta görs med ett kommando-objekt. Du använder ett kommando-objekt för att skicka SQL-satser till databasen. • Ett kommando-objekt använder ett anslutningsobjekt för att veta vilken databas som ska kommuniceras med. • Du kan använda ett kommando-objekt ensamt för att utföra ett kommando direkt, eller tilldela en referens till en SqlDataAdapter. © Winstrand Development 2013-01-30 7 ADO.NET Objekt SqlDataReader objekt • Många operationer kräver att du bara får en ström av data för läsning. • Tillåter dig att få resultatet av en SELECT-sats från ett kommando-objekt. • Av prestandaskäl är de data som returneras från objektet är endast en ström av data. • Detta innebär att du bara kan ta data från strömmen på ett sekventiellt sätt • Detta är bra för hastighet, men om du behöver manipulera data, då är det bättre att arbeta med DataSet-objekt. © Winstrand Development 2013-01-30 8 ADO.NET Objekt DataSet-objekt • Är en in-memory representation av data. • Innehåller flera DataTable-objekt som innehåller kolumner och rader, precis som vanliga databastabeller. • Du kan även definiera relationer mellan tabeller för att skapa överordnade och underordnade relationer. • Är särskilt utformat för att hantera data i minnet och för att stödja frånkopplade operationer på data när ett sådant scenario krävs. • Är ett objekt som används av alla uppgiftslämnarna, varför den inte har ett DataProvider specifik prefix. © Winstrand Development 2013-01-30 9 ADO.NET Objekt SqlDataAdapter Objekt • Ibland när man arbetar med främst skrivskyddad data och sällan behöver göra ändringar i den underliggande datakällan eller när vissa situationer kräver cachning av data i minnet för att minimera antalet databasanrop för uppgifter som inte ändras. • Då är det lämpligt att använda sig av SqlDataAdapter-objektet som gör det enkelt för dig att utföra dessa saker genom att hjälpa till att hantera data i en frånkopplad läge. © Winstrand Development 2013-01-30 10 ADO.NET Objekt SqlDataAdapter Objekt • Populerar ett DataSet-objekt när man läser data och skriver in alltsammans när man har gjort ändringar • Innehåller en referens till anslutnings-objektet och öppnar och stänger anslutningen automatiskt när man läser från eller skriver till databasen. • Dessutom innehåller kommandoobjekt referenser för SELECT, INSERT, UPDATE och DELETE operationer på datan. • Det definieras en adapter för varje tabell i ett DataSet och det kommer att sköta all kommunikation med databasen för dig. • Allt du behöver göra är att tala om för adaptern när man laddar från eller skriver till databasen. © Winstrand Development 2013-01-30 11 Skapa SQL koppling • Skapa ett SQL kommando SqlConnection conn = new SqlConnection(@"server=.\SQLExpress;” + ”database=spo12;integrated Security=SSPI;"); SqlDataReader rdr = null; try { conn.Open(); SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", conn); rdr = cmd.ExecuteReader(); while (rdr.Read()) { txtUsers.Text = txtUsers.Text + rdr[1] + " " + rdr[2] + " [" + rdr[0] + "]\n"; } } finaly { if(rdr != null) { rdr.Close(); } if (conn != null) { conn.Close(); } } © Winstrand Development 2013-01-30 12 Skapa ett SqlCommand objekt • I likhet med andra C #-objekt, när man instansierar ett SqlCommand-objekt med en ny instans deklaration, enligt följande: SqlCommand cmd = new SqlCommand("SELECT firstname FROM Users", conn); • Detta är ett typiskt sätt att instansiera ett SqlCommand-objekt. Det tar en strängparameter som innehåller det kommando du vill köra och en hänvisning till ett SQLConnection objekt. © Winstrand Development 2013-01-30 13 Ställa en fråga • När du använder SQL-kommandot SELECT får du ett data-set. För att åstadkomma detta med SqlCommand-objektet använder du ExecuteReader-metoden som returnerar ett SqlDataReaderobjekt. • Exemplet nedan visar hur du använder SqlCommand objektet för att få ett SqlDataReader objekt: SqlCommand cmd = new SqlCommand ("SELECT firstname FROM Users", conn); SqlDataReader rdr = cmd.ExecuteReader(); I exemplet ovan, instansierar vi SqlCommand-objektet, skickar med kommandosträngen och anslutningsobjektet till konstruktorn. • Då kan vi få ett SqlDataReader-objekt genom att anropa ExecuteReader -metoden i cmd. © Winstrand Development 2013-01-30 14 Infoga data • Om du vill infoga data i en databas, använder man ExecuteNonQuery-metoden från SqlCommandobjektet. Följande kod visar hur du infogar data i en databas tabell: // Förbereda kommandosträng string insertString = @" INSERT INTO Users (firstname, lastname) VALUES (’Arne’, ’Andersson’’s’)"; SqlCommand cmd = new SqlCommand(insertString, conn); cmd.ExecuteNonQuery(); • Denna SqlCommand instansiering är bara lite annorlunda från vad du har sett förut, men det är i princip samma. © Winstrand Development 2013-01-30 15 • Istället för en sträng som första parameter i SqlCommand konstruktorn använder vi en variabel, insertString. • Lägg märke till de två apostroferna('') i insertString texten för ordet ”Andersson’’s”. Det är så man ’escapar’ apostrofer för att få strängen att fylla kolumnen ordentligt. • En annan iakttagelse att göra om insert-kommandot är att vi uttryckligen anger kolumnerna firstname och lastname. Tabellen Users har ett primärnyckel-fält med namnet id. Vi utelämnade detta ur listan eftersom SQL Server kommer att lägga till detta fält själv. Försöker lägga till ett värde till ett primärnyckel-fält, t.ex. id, kommer det att genereras ett undantag. • För att utföra detta kommando kallar vi helt enkelt ExecuteNonQuery-metoden från SqlCommand instansen cmd. © Winstrand Development 2013-01-30 16 Uppdatera data • ExecuteNonQuery-metoden används också för att uppdatera data. Följande kod visar hur du uppdaterar data: // Förbereda kommandosträng string updateString = @" UPDATE Users SET firstname=’Bamse’ WHERE lastname=’Andersson’’s’"; SqlCommand cmd = new SqlCommand(updateString); cmd.Connection = conn; cmd.ExecuteNonQuery(); • Återigen satte vi SQL-kommandot till en sträng variabel, men den här gången använder vi en annan SqlCommand konstruktor som bara tar strängen. I steg 2, tilldelar vi SQLConnection objektet, conn till Connection egenskapen för cmd. © Winstrand Development 2013-01-30 17 Uppdatera data (forts) • Detta skulle ha skett på samma sätt om konstruktorn används med två parametrar. Det visar att man kan ändra anslutningsobjektet när som helst. • ExecuteNonQuery-metoden utför uppdaterings-kommandot. © Winstrand Development 2013-01-30 18 Ta bort data • Du kan också radera data med hjälp av ExecuteNonQuery-metoden. Följande exempel visar hur du tar bort en post från en databas med ExecuteNonQuery: // Förbereda kommandosträng string deleteString = @" DELETE FROM Users WHERE lastname=’Andersson’’s’"; SqlCommand cmd = new SqlCommand(); cmd.CommandText = deleteString; cmd.Connection = conn; cmd.ExecuteNonQuery(); • I exemplet används SqlCommand konstruktorn utan parametrar. Istället sätter man explicit CommandText och Connection egenskaperna i SqlCommand-objektet cmd. © Winstrand Development 2013-01-30 19 Ta bort data (forts) • Vi kunde också använt något av de två föregående sätten i anropet av SqlCommand konstruktorn, med samma resultat. • Detta visar att du kan ändra både kommandosträngen och anslutningen när som helst. • Med ExecuteNonQuery-metodanropet skickar man kommando till databasen. © Winstrand Development 2013-01-30 20 • SqlDataReader Objekt • Att skapa en instans av SqlDataReader är lite annorlunda än på vilket sätt du initiera andra ADO.NET objekt. Du måste kalla på ExecuteReader från ett kommando-objekt, så här: SqlDataReader rdr = cmd.ExecuteReader(); ExecuteReader är en metod i SqlCommand objektet cmd, det returnerar en SqlDataReader instans. Man behöver skapa ett SqlDataReader objekt för att kunna ta hand om resultatet från de frågor man ställer med SqlCommand-objektet, som nämnts tidigare. © Winstrand Development 2013-01-30 21 SqlDataReader • Använda inläst data • Såsom förklarats tidigare, återgår SqlDataReader data via en sekventiell ström. För att läsa dessa data måste du hämta data från en tabell rad-för-rad När en rad har läst, är den tidigare raden inte längre tillgänglig. För att läsa den raden igen, skulle du behöva skapa en ny instans av SqlDataReader och läsa igenom dataströmmen igen. • Den typiska metoden för läsning från dataströmmen returneras av SqlDataReader är att loopa igenom varje rad med en while-slinga. Följande kod visar hur du gör detta: © Winstrand Development 2013-01-30 22 while (rdr.Read()) { // get the results of each column string contact = (string)rdr["ContactName"]; string company = (string)rdr["CompanyName"]; string city = (string)rdr["City"]; // print out the results Console.Write("{0,-25}", contact); Console.Write("{0,-20}", city); Console.Write("{0,-25}", company); Console.WriteLine(); } © Winstrand Development 2013-01-30 23 • Lägg märke till metodanropet rdr.Read() i villkoret för while. • Returvärdet från Read är bool och true så länge det finns fler poster att läsa. När den sista posten i dataströmmen är läst, så returneras false. • Tidigare, extraherade vi den första kolumnen från raden med hjälp av SqlDataReader indexeraren, dvs rdr[0]. • Du kan extrahera varje kolumn i raden med en numerisk indexerare som denna. I exemplet ovan används en strängindexerare, där strängen är kolumnnamnet från SQL-fråga (tabell kolumnnamn om du använde en asterisk, *). String indexerare gör det mycket mer lättläst, vilket gör koden lättare att underhålla. • Oavsett vilken typ av indexerarparameter, kommer en SqlDataReader indexerare returnera ett typobjekt. Detta är anledningen till typkonverteringen i exemplet ovan. • När värdena utvinns, kan du göra vad du vill med dem, till exempel skriva ut dem. © Winstrand Development 2013-01-30 24 Skapa SQL koppling • Skapa ett SQL kommando SqlConnection conn = new SqlConnection(@"server=.\SQLExpress;” + ”database=spo12;integrated Security=SSPI;"); SqlDataReader rdr = null; try { conn.Open(); SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", conn); rdr = cmd.ExecuteReader(); while (rdr.Read()) { txtUsers.Text = txtUsers.Text + rdr[1] + " " + rdr[2] + " [" + rdr[0] + "]\n"; } } finaly { if(rdr != null) { rdr.Close(); } if (conn != null) { conn.Close(); } } © Winstrand Development 2013-01-30 25 • Länkar till bra sidor på nätet • http://www.w3schools.com/ado/default.asp © Winstrand Development 2013-01-30 26