ADO.Net ADO.Net ADO.Net ADO.Net
Transcription
ADO.Net ADO.Net ADO.Net ADO.Net
ADO.Net ActiveX Data Object .Net (ADO.Net) ADO.Net API d’accès (local ou distant) à une source de données : SGBD, tableur, fichier, messagerie, … Fonctionne selon un principe client/serveur (local ou distant) • client = le programme (C#, VB, C++, …) • serveur = la source de données Lionel Seinturier INRIA Futurs Lille – Projet JACQUARD Université Pierre & Marie Curie Principe • le programme ouvre une connexion • il envoie des requêtes SQL • il récupère les résultats • ... • il ferme la connexion [email protected] 30/8/04 ADO.Net 1 Lionel Seinturier ADO.Net 2 ADO.Net Lionel Seinturier ADO.Net ActiveX Data Object .Net (ADO.Net) Historique ODBC Accès SGBD • API d'interaction avec un SGBD • nombreuses utilisations - sauvegarde de données de manière sûre - exploration du contenu d'un SGBD - client/serveur 3 tiers évolutions DAO C++ VB RDO unification OLE-DB ts langages – API COM présentation traitement simplification (+ haut niveau) donnée ADO ADO.Net framework .Net client ADO.Net serveur d'applications 3 SGBD ADO.Net Lionel Seinturier ADO.Net 4 Lionel Seinturier ADO.Net ADO.Net Fournisseur (provider) ADO.Net Connection string ADO.Net Implémentation de l’API pour un type de sources de données Identifie la source de données à laquelle on se connecte Principaux providers • chaîne de caractères • liste de couples propriété=valeur • format dépend du provider • SQL Server (>= 7.0) • OLE-DB (SQL Server < 7.0, …) • ODBC (Excel, Access, …) • MySQL •… System.Data.SqlClient.SqlConnection System.Data.OleDb.OleDbConnection System.Data.Odbc.OdbcConnection http://sourceforge.net/projects/mysqlnet/ • ODBC "Driver={SQL Server};Server=localhost;Database=mydb;Uid=login;Pwd=passwd" • OLE-DB “Provider=sqloledb;Data Source=…;Database=…;User Id=…;Password=…” •… voir http://geekswithblogs.net/brcraju/archive/2004/02/03/1689.aspx Fournisseur Chaque provider = une classe OLE-DB ODBC ADO.Net 5 Exemple Lionel Seinturier ADO.Net 6 ADO.Net Lionel Seinturier ADO.Net Utilisation de ADO.Net Utilisation de ADO.Net (suite) L'ensemble de l'API ADO.Net est définie dans System.Data 3. Récupération du résultat 1. Ouverture d'une connexion avec la base comptes reader.Read() OdbcConnection cx = new OdbcConnection("Driver={SQL Server};Server=localhost;Database=pubs;"); cx.Open(); reader.GetString(int column) retourne vrai tant qu'il reste des enregistrements dans le résultat et positionne le curseur sur l'enregistrement suivant (ex. : reader.GetString(0) ) retourne la valeur de la colonne 0 de type String de l’enregistrement courant 2. Envoi d'une requête SELECT GetInt32, GetBoolean, GetByte, GetDouble, GetFloat OdbcCommand cmd = new OdbcCommand("SELECT * FROM ages"); OdbcDataReader reader = cmd.ExecuteReader(); idem pour des colonnes de type int, boolean, byte, double ou float Envoi d'une requête CREATE, INSERT ou UPDATE OdbcCommand cmd = new OdbcCommand("INSERT INTO ages VALUES ('toto',12)"); cmd.ExecuteNonQuery(); ADO.Net 7 Lionel Seinturier while( reader.Read() ) { String nom = reader.GetString(0); int age = reader.GetInt32(1); Console.WriteLine( nom + " a " + age + " ans" ); } ADO.Net 8 Lionel Seinturier ADO.Net ADO.Net Utilisation de ADO.Net (code complet) Types de requêtes SQL using System.Data; using System.Data.Odbc; • "normale" - interprétée à chaque exécution public class TestADONet { • précompilée - paramétrable - préparée pour être exécutée plusieurs fois - gérée par le programme public static void Main( String[] args ) { OdbcConnection cx = new OdbcConnection( "Driver={SQL Server};Server=localhost;Database=pubs;" ); cx.Open(); • procédure stockée - paramétrable - écrite dans le langage interne du SGBD (ex SQL Server Transac-SQL) - gérée par le SGBD OdbcCommand cmd = new OdbcCommand("SELECT * FROM ages",cx); OdbcDataReader reader = cmd.ExecuteReader(); while (reader.Read()) { string nom = reader.GetString(0); int age = reader.GetInt32(1); Console.WriteLine( nom + " a " + age + " ans" ); } + masque schéma base + meilleures perf + validées par rapport schéma base cx.Close(); - langage propriétaire (- évolution) - risque de mélange logiques traitement/donnée } } ADO.Net 9 Lionel Seinturier ADO.Net ADO.Net 10 Lionel Seinturier ADO.Net Requêtes SQL précompilées Procédures stockées 1. Possibilité de définition de 1 ou +sieurs paramètres ! caractères ? Exemple de procédure stockée Transact-SQL (SQL Server) CREATE PROCEDURE [pubs].[GetRange] @age int AS SELECT nom FROM ages WHERE age < @age GO OdbcCommand cmd = new OdbcCommand ("SELECT * FROM ages WHERE nom=? AND age>?",cx); 2. Valeurs des paramètres ajoutés à la commande cmd.Parameters.Add(new OdbcParameter("","Bob"),cx); cmd.Parameters.Add(new OdbcParameter("",Convert.ToInt32(5)),cx); Le code d’appel de la procédure • new OdbcParameter( string name, object value ) • paramètres ajoutés dans l'ordre de leur définition dans la requête • name non significatif dans ce contexte (voir procédure stockée) OdbcCommand cmd = new OdbcCommand("GetRange",cx); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add( new OdbcParameter("age",Convert.ToInt32(5) ); OdbcDataReader reader = cmd.ExecuteReader(); ... 3. Exécution de la requête OdbcDataReader reader = cmd.ExecuteReader(); ... ADO.Net 11 Lionel Seinturier ADO.Net 12 Lionel Seinturier ADO.Net ADO.Net Transactions Transactions Groupes de requêtes devant être exécutés de façon indivisible Exemple La transaction doit être CREATE TABLE comptes (nom VARCHAR(30) PRIMARY KEY, solde FLOAT CHECK(solde>=0) ); - validée (commit) ! les résultats ne sont visibles qu'à partir de ce moment - ou annulée (rollback) OdbcCommand cmd1, cmd2; cmd1 = new OdbcCommand("UPDATE comptes SET solde=solde+montant WHERE nom='Paul'",cx); cmd2 = new OdbcCommand("UPDATE comptes SET solde=solde-montant WHERE nom='Bob'",cx); OdbcTransaction trans = cx.BeginTransaction(); OdbcCommand cmd1 = new OdbcCommand("INSERT INTO ages VALUES ('Pierre',12)",cx); OdbcCommand cmd2 = new OdbcCommand("UPDATE ages SET age=15 WHERE nom='Joe'",cx); OdbcTransaction trans = cx.BeginTransaction(); cmd1.Transaction = trans; cmd2.Transaction = trans; cmd1.ExecuteNonQuery(); cmd2.ExecuteNonQuery(); déclaration du début de la transaction trans.Commit(); validation de la transaction ADO.Net 13 Lionel Seinturier try { cmd1.Transaction = trans; cmd2.Transaction = trans; cmd1.ExecuteNonQuery(); cmd2.ExecuteNonQuery(); trans.Commit(); } catch( Exception e ) { trans.Rollback(); } ADO.Net 14 ADO.Net Lionel Seinturier ADO.Net Accès aux données en mode déconnecté Accès aux données en mode déconnecté • par défaut c/s connecté vers SGBD + 1 seule copie des données (SGBD) + mises à jour simples • datasets : représentation mémoire des données d'un SGBD SELECT … adapter.Update(dataset) rés eau DataSet connecté vs non connecté n messages petite taille vs 1 message grande taille SELECT … rés eau Data Adapter SGBD adapter.Fill(dataset) DataAdapter : gère liaison mémoire (DataSet) – SGBD ! contient les requêtes SQL (select, update, insert) associées aux données Déconnecté • pouvoir consulter/modifier les données off line • économiser les ressources réseaux (connexions moins longues) • travailler sur des données en mémoire plutôt que directement sur un SGBD ADO.Net 15 Lionel Seinturier ADO.Net 16 Lionel Seinturier ADO.Net ADO.Net DataSet Exemple d'utilisation d'un DataSet Un DataSet contient OdbcConnection cx = new OdbcConnection( "Driver={SQL Server};Server=localhost;Database=pubs;" ); cx.Open(); • des DataTable données sous forme de table - des DataColumn - nom, type, propriétés (autoincrement, unique, readonly, maxlength, …), … - des DataRow - valeurs - des DataConstraint • des DataRelation relation entre 2 DataTable • une DefaultView Un DataSet peut être • consulté • modifié (valeurs, lignes) • sauvegardé/chargé en XML ! mise à jour BD lors de Update() ADO.Net 17 Lionel Seinturier OdbcDataAdapter adapter = new OdbcDataAdapter(); adapter.SelectCommand = new OdbcCommand("SELECT * FROM comptes",cx); OdbcCommandBuilder builder = new OdbcCommandBuilder(adapter); DataSet dataset = new DataSet(); adapter.Fill(dataset); cx.Close(); for( int i=0 ; i<dataset.Tables.Count ; i++ ) { DataTable table = dataset.Tables[i]; DataColumnCollection columns = table.Columns; for( int j=0 ; j<table.Rows.Count ; j++ ) { DataRow row = table.Rows[j]; Console.WriteLine("Row "+j+": "+row["nom"]+" "+row["solde"]); } } ADO.Net ADO.Net 18 Lionel Seinturier ADO.Net Mise à jour d'un DataSet DataView Modification d'une valeur Vue (pas de copie des données) sur une Datatable table.Rows[0][0] = "Bill"; adapter.Update(dataset); • séléction • tri Ajout d'une ligne Mise à jour données dans la vue = maj des données dans la DataTable DataRow myDataRow = table.NewRow(); myDataRow["nom"] = "John"; myDataRow["solde"] = 123; table.Rows.Add(myDataRow); adapter.Update(dataset); DataView view = new DataView(table); view.RowFilter = "nom='Bob'"; // sélection de(s) Bob for( int i=0 ; i < view.Count ; i++ ) { view.Delete(i); // suppression aussi dans la DataTable } view.Sort = "nom, age DESC"; // d'abord pas nom puis par age décroissant Expression de sélection "à la SQL" - opérateur LIKE - fonctions sum, avg, count, min, max ADO.Net 19 Lionel Seinturier ADO.Net nom LIKE '*ob*' 20 Lionel Seinturier ADO.Net ADO.Net Utilisation des DataSet avec les DataGrid Trou de sécurité (bien connu) DataGrid Attaque "SQL injection" à partir de formulaires Web composants WinForm et WebForm d'édition de données tabulaires CREATE TABLE notes ( netudiant text, note float ); Formulaire traité ASP (idem PHP, JSP, …) String num = ... String requete = "SELECT * FROM notes WHERE netudiant='"+num+"'"; OdbcCommand cmd = new OdbcCommand(requete,cx); datagrid.DataSource = dataset.Tables[0]; datagrid.DataBind(); Saisie '; SELECT * FROM notes WHERE ''=' requete = DataGrid Data Adapter DataSet ADO.Net 21 SELECT * FROM notes WHERE netudiant=''; SELECT * FROM notes WHERE ''='' SGBD Lionel Seinturier ! toutes les notes !! ADO.Net ADO.Net ≠ niv. isolation ADO.Net Lionel Seinturier ADO.Net Comparaison ADO.Net - JDBC c/s accès désignation initialisation connexion commande curseur résultat curs. multi-dir curs. maj deconnecté transaction 22 Comparaison ADO.Net - JDBC ADO.Net JDBC oui provider Driver=… new … Open() …Command …DataReader non non DataSet cx.BeginTransaction() trans.Commit() trans.Rollback() oui oui driver jdbc:mysql://… Class.forName("…") DriverManager.getConnection Statement/PreparedStatement/CallableState ResultSet oui oui RowSet (JDBC 3.0) cx.setAutoCommit(false) cx.commit() cx.rollback() oui 23 Lionel Seinturier ≠ niv. isolation méta-données batch pool de cx ADO.Net ADO.Net JDBC oui oui non oui (provider) oui oui oui oui (JNDI) 24 Lionel Seinturier