DAO - Data Access Object Problmatique et dfinitions Diagramme de classes du modle DAO Diagramme de squences du modle DAO Oprations CRUD DAO et Exceptions Utilisation des DAO DAO t C i DAO et Connexion DAO et Transaction DAO et Hritage Fabrique de DAO Prsentation du TP JDBC/DAO MaudeManouvrier - Univ. Paris Dauphine 42 Modles de persistance : DAO - Data Access Object (1/2) Problmesrsoudre: Variationducodedepersistanceenfonction: Du type de support de persistance (BD relationnelle BD objet Du type de support de persistance (BD relationnelle, BD objet, fichiers, etc.) DesdiffrentesimplmentationsdesfournisseursdeSGBD Difficult changer de support de persistance en cas dimbricationducodedepersistanceet ducodemtier Solution: Sparationdesentres sortiesdesclassesmtier MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] et du Core J2EE Patterns - Data Access Object 2001-2002 de Sun Microsystems http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 43 Sparationdesentres-sortiesdesclassesmtier Utilisation dun objet particulier - objet daccs aux donnes - pour abstraireet encapsuler lesaccsauxdonnes DAO: Motif deconception galement connusous le nomdeData Mapper (M. Fowler) 2 Modles de persistance : DAO - Data Access Object (2/2) DiffrenceentreunDAOet unactive record : Les objets manipulant les donnes nont pas accs au code permettant de sauvegarder ces donnes dans la code permettant de sauvegarder ces donnes dans la base UtilitdesDAO: Faciliter lamodificationdumodledebasededonnes Factoriser lecodedaccsauxdonnes MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] et du Core J2EE Patterns - Data Access Object 2001-2002 de Sun Microsystems http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 44 Faciliter loptimisationdes accs labaseenles regroupant auseindobjetsparticuliers Placement des DAO dans la couche daccs aux donnes Diagramme de classes du modle de conception DAO (1/2) MaudeManouvrier - Univ. Paris Dauphine 45 Figure reprise de Core J2EE Patterns - Data Access Object 2001-2002 de Sun Microsystems http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 3 Diagramme de classes du modle de conception DAO (2/2) Objet mtier (Business Object) : Donnesvuespar leclient Objet ncessitant laccs et lestockagededonnes depuis lesupport de Objet ncessitant l accs et lestockagededonnes depuis lesupport de persistance Objet pouvant treimplmentpar uneEJB session, EJ B entit, or tout autre objet J ava en association avec un servlet ou une helper bean qui accdentlasourcededonnes. Objet daccs aux donnes (Data Access Object) : Abstraction delimplmentation delaccs aux donnes pour rendrecet accstransparentvisvisdelobjetmtier MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] et du Core J2EE Patterns - Data Access Object 2001-2002 de Sun Microsystems http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 46 Dlgation des oprations de sauvegarde et de rcupration de lobjet mtier verslobjetdaccsauxdonnes Source de donnes (Data source) : BDrelationnelle, BDobjet, fichiers, etc. Objet de transfert (Data Transfert Object - DTO) : Objet detransport des donnesentrelacouchedaccsauxdonneset lacouchemtier Diagramme de squences du modle DAO MaudeManouvrier - Univ. Paris Dauphine 47 Figure reprise de Core J2EE Patterns - Data Access Object 2001-2002 de Sun Microsystems http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 4 Oprations CRUD (1/5) Implmentation par les DAO des 4 oprations debasedepersistanceCRUD: Create : crationdunenouvelleentit Retrieve : recherche dune ou plusieurs entits Update : modificationduneentit MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 48 Delete : suppressionduneentit Plusieurs variantes de signatures pour ces mthodesdanslesDAO Oprations CRUD (2/5) Create Paramtres: ltat delanouvelleentittransmispar U i d d d ib l i l Unesriedeparamtres detypedes attributs solution la pluscourante Unobjet DTO Unobjet mtier rendrepersistant Typeretour : voi d MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 49 bool ean - pour indiquer si lacrationapuavoir lieu Un identificateur dentit utile en cas de gnration automatiquedidentificateur Unobjet mtier ouunDTOcorrespondant lentitcre 5 Oprations CRUD (3/5) Retrieve Retour dunobjet P t id tifi t d l tit h h Paramtre: identificateur delentitrecherche Retour : un objet mtier ou un DTO contenant les donnes de lentitrecherche Retour dunecollection dobjets Paramtre: objet ouvaleurscritresderechercheouunobjet exemple R ll i MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 50 Retour : Resul t Set ou RowSet ou collection (Col l ect i on, Set , Li st ) dobjetsmtier ouDTO Retour dunevaleur calcule Possibilitdecalculer unevaleur partir desobjetsenmmoire Meilleur choix: interroger directement labase Oprations CRUD (4/5) Update Diversesvariantesdeparamtres: Identificateur +valeurs (plusieurs paramtres pour lesvaleursouunDTO) Objet mtier correspondant lentit modifier danslabase Typeretour : MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 51 Typeretour : voi d bool ean - pour indiquer si la mise jour a pu avoir lieu 6 Oprations CRUD (5/5) Delete Diversesvariantesdeparamtres: Identificateur delentitsupprimer danslabase Objet mtier correspondant lentit supprimer danslabase Typeretour : MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 52 voi d bool ean - pour indiquer si la suppression a pu avoir lieu DAO et Exceptions Possibilitdelancer ouattraper des exceptions Possibilitdelancer ouattraper des exceptions dans les mthodes des DAO car oprations dentres/sorties Ne pas lier les exceptions un type de DAO particulier pour pouvoir facilement enchanger MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 53 particulier pour pouvoir facilement enchanger 7 Utilisation des DAO (1/3) 2stratgies: DAO rfrenc par chaque objet mtier pour sa propre persistance persistance Aucune connaissance des DAO par les programmes qui manipulent lesobjetsmtiers Ncessit dune rfrence vers le DAO utilis (ex. obtenuepar unemthodest at i c delaclasseDAO) DAO directement manipuls par les programmes qui i l l bj i MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 54 manipulent lesobjetsmtier PasderfrenceauxDAOpar lesobjetsmtier Stratgielaplussouvent utilise - PertedelapuretdelaprogrammationOO Utilisation des DAO (2/3) class Departement { private DepartementDAO dao; Rfrence au DAO Exemple pour la stratgie 1 : public void devientPersistant() { dao = getDAO(); dao.insertOrUpdate(this); } private DepartementDAO getDAO() { if (dao == null) Possibilit de passer un DTO MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 55 if (dao null) DepartementDAO.getDAO(); return dao; } ... } Grer les exceptions 8 Utilisation des DAO (3/3) DepartementDAO deptDAO = DepartementDAO.getDAO(); int idDepartement = deptDAO.create("1","MIDO",...); Exemple pour la stratgie 2 : p p ( , , ); Departement dept = deptDAO.findById(idDepartement); deptDAO.update(idDepartement, ...); DTO ou objet mtier Nouvelles valeurs pour lentit D dept.setNom("Mathmatiques, MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 56 Departement List<Departement> liste = deptDAO.findAll(); dept.setNom( Mathmatiques, Informatique, Dcision et Organisation"); deptDAO.update(dept); ou bien DAO et Connexion Connexion et dconnexion au sein des mthodesdesDAO - Cot lev sans utilisation de pool de connexions Mthodes spcifiques de connexion et de dconnexionspar DAO MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 57 + Utilisation dune mme connexion par plusieursmthodesduDAO 9 DAO et Transaction Le+souvent : dbut et findelatransaction i d h th d d DAO greauseindechaquemthodedeDAO Dans les cas complexes : intervention au sein dune mme transaction de plusieurs mthodes de DAO associs diffrents typesdobjetsmtier MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 58 typesd objetsmtier Gestiondestransactionspar leclient DAO et Hritage (1/2) Problme : rendre persistantes via une classe fille des proprits pr i vat e de sa classe fille des proprits pr i vat e de sa classe mre Solution: Utilisationdunehirarchieparallle declassesmappers TransmissionauDAOdesdonnesncessaires MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 59 TransmissionauDAOdesdonnesncessaires pour les changes avec la BD par chaque classemapper 10 DAO et Hritage (2/2) MaudeManouvrier - Univ. Paris Dauphine repris de http://www.martinfowler.com/eaaCatalog/inheritanceMappers.html 60 Exemple de hirarchie de classes Exemple de hirarchie de classes mappers Fabrique de DAO (1/10) DAO Factory : U ili i d f b i / Utilisationdunefabriquepour crer/rcuprer un DAO et donc cacher le type concret de la classeduneinstanceencration Fabrique abstraite : pour cacher le type rel dunensembledefabriquesconcrtes MaudeManouvrier - Univ. Paris Dauphine repris et adapt de [Grin05] 61 d unensembledefabriquesconcrtes Fabriques concrtes : pour fournir tous les DAO (de chaque objet mtier) associs une certainesourcededonnes 11 Fabrique de DAO (2/10) Fabrique abstraite Fabriques concrtes MaudeManouvrier - Univ. Paris Dauphine repris de http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 62 DAO crs Fabrique de DAO (3/10) Cration de tous les DAO associs une source de donnes par la fabrique concrte MaudeManouvrier - Univ. Paris Dauphine repris de http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 63 12 Fabrique de DAO (4/10) Exemple : MaudeManouvrier - Univ. Paris Dauphine repris de http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 64 Fabrique de DAO (5/10) // Abstract class DAO Factory public abstract class DAOFactory { // List of DAO types supported by the factory public static final int CLOUDSCAPE = 1; public static final int ORACLE = 2; public static final int SYBASE = 3; ... // There will be a method for each DAO that can be created. // The concrete factories will have to implement these methods. public abstract CustomerDAO getCustomerDAO(); public abstract AccountDAO getAccountDAO(); public abstract OrderDAO getOrderDAO(); ... bli t ti DAOF t tDAOF t (i t hi hF t ) { MaudeManouvrier - Univ. Paris Dauphine repris de http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 65 public static DAOFactory getDAOFactory(int whichFactory) { switch (whichFactory) { case CLOUDSCAPE: return new CloudscapeDAOFactory(); case ORACLE : return new OracleDAOFactory(); case SYBASE : return new SybaseDAOFactory(); ... default : return null; } } } 13 Fabrique de DAO (6/10) // Cloudscape concrete DAO Factory implementation public class CloudscapeDAOFactory extends DAOFactory { // method to create Cloudscape connections public static Connection createConnection() { // Use DRIVER and DBURL to create a connection // Use DRIVER and DBURL to create a connection // Recommend connection pool implementation/usage } public CustomerDAO getCustomerDAO() { // CloudscapeCustomerDAO implements CustomerDAO return new CloudscapeCustomerDAO(); } public AccountDAO getAccountDAO() { // CloudscapeAccountDAO implements AccountDAO return new CloudscapeAccountDAO(); MaudeManouvrier - Univ. Paris Dauphine repris de http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 66 p (); } public OrderDAO getOrderDAO() { // CloudscapeOrderDAO implements OrderDAO return new CloudscapeOrderDAO(); } ... } Fabrique de DAO (7/10) // Interface that all CustomerDAOs must support public interface CustomerDAO { public int insertCustomer(...); public boolean deleteCustomer(...); public Customer findCustomer(...); public boolean updateCustomer(...); public RowSet selectCustomersRS(...); public Collection selectCustomersTO( ); MaudeManouvrier - Univ. Paris Dauphine repris de http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 67 public Collection selectCustomersTO(...); ... } 14 Fabrique de DAO (8/10) // CloudscapeCustomerDAO implementation of the CustomerDAO interface. // This class can contain all Cloudscape specific code and SQL statements. // The client is thus shielded from knowing these implementation details. public class CloudscapeCustomerDAO implements CustomerDAO { public CloudscapeCustomerDAO() { // initialization } p p () { // } // The following methods can use CloudscapeDAOFactory.createConnection() // to get a connection as required public int insertCustomer(...) { // Implement insert customer here. // Return newly created customer number or a -1 on error } public boolean deleteCustomer(...) { // Implement delete customer here // Return true on success, false on failure MaudeManouvrier - Univ. Paris Dauphine repris de http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 68 } public Customer findCustomer(...) { // Implement find a customer here using supplied argument values // as search criteria // Return a Transfer Object if found, // Return null on error or if not found } ... } Fabrique de DAO (9/10) //Customer Transfer Object public class Customer implements java io Serializable { public class Customer implements java.io.Serializable { // member variables int CustomerNumber; String name; String streetAddress; String city; ... MaudeManouvrier - Univ. Paris Dauphine repris de http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 69 // getter and setter methods ... ... } 15 Fabrique de DAO (10/10) // Client code // create the required DAO Factory DAOFactory cloudscapeFactory = DAOFactory.getDAOFactory(DAOFactory.DAOCLOUDSCAPE); // Create a DAO C t DAO tDAO l d F t tC t DAO() CustomerDAO custDAO = cloudscapeFactory.getCustomerDAO(); // create a new customer int newCustNo = custDAO.insertCustomer(...); // Find a customer object. Get the Transfer Object. Customer cust = custDAO.findCustomer(...); // modify the values in the Transfer Object. cust.setAddress(...); cust.setEmail(...); // update the customer object using the DAO custDAO.updateCustomer(cust); // d l t t bj t MaudeManouvrier - Univ. Paris Dauphine repris de http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html 70 // delete a customer object custDAO.deleteCustomer(...); // select all customers in the same city Customer criteria=new Customer(); Criteria.setCity("New York"); Collection customersList = custDAO.selectCustomersTO(criteria); // returns customersList - collection of Customer Transfer Objects. // iterate through this collection to get values. ... TP JBDC/DAO (1/10) ht t p: / / www. l amsade. dauphi ne. f r / ~manouvr i / HI BERNATE/ TP_J DBC/ TP_J DBC. ht ml Donnes: Unebasededonnesexemple(sousformedescripts SQL) gresous Unebasededonnesexemple(sousformedescripts SQL), gresous PostgreSQL Un programme J ava exemple (Test J DBCPost gr esql . j ava) contenantlesprincipalescommandesJ DBC Une classe Java (Conf i gConnect i on. j ava) pour grer les connexionslabasededonnes Uneclasseexemple(typeActive record - Depar t ement . j ava) MaudeManouvrier - Univ. Paris Dauphine 71 Unprogramme(Cr eer Depar t ement . j ava) permettant detester la classe Travail raliser : Dvelopper 3DAO 16 TP JBDC/DAO (2/10) Connexion la BD import java.sql.*; public class TestJDBCPostgresql { Connection db=null; // Connexion la BD Statement sql=null; // Curseur pour la requte tate e t sq u ; // u seu pou a equte DatabaseMetaData dbmd; // Mta-donnes issues du driver public TestJDBCPostgresql(String argv[]) throws ClassNotFoundException, SQLException, java.io.IOException { String database = argv[0]; String username = argv[1]; String password = argv[2]; MaudeManouvrier - Univ. Paris Dauphine 72 String password = argv[2]; Class.forName("org.postgresql.Driver"); // Rcupration du driver db = DriverManager.getConnection("jdbc:postgresql:"+database, username, password); // Connexion TP JBDC/DAO (3/10) Excution dune requte de MJ sql = db.createStatement(); // Cration du curseur pour la requte String sqlText = "CREATE TABLE Note ( Note_ID SERIAL, " + "Etudiant_ID integer, " + "Inscription ID integer " + "Inscription_ID integer," + "Note real," + "CONSTRAINT PK_Notes PRIMARY KEY (Note_ID)," + "CONSTRAINT FK_Notes_Etudiant FOREIGN KEY (Etudiant_ID) " + " REFERENCES Etudiant (Etudiant_ID)," + " CONSTRAINT FK_Notes_Inscription " + " FOREIGN KEY (Inscription_ID) " + " REFERENCES Inscription (Inscription_ID) " + ) MaudeManouvrier - Univ. Paris Dauphine 73 " );"; System.out.println("Executing this command: "+sqlText+"\n"); sql.executeUpdate(sqlText); // Excution de la requte db.commit(); // Validation de la requte 17 TP JBDC/DAO (4/10) Excution dune requte dinterrogation sqlText="SELECT capacite FROM Salle " + "WHERE Batiment ='B' " + "AND Numero_Salle='020' FOR UPDATE"; S t t i tl ("E ti thi d "+ lT t+"\ ") System.out.println("Executing this command : "+sqlText+"\n"); ResultSet rset = sql.executeQuery(sqlText); // Pour afficher le rsultat de la requte while (rset.next()) { System.out.println("Capacit de la salle B020 : " + rset.getInt(1) + "\n"); MaudeManouvrier - Univ. Paris Dauphine 74 } TP JBDC/DAO (5/10) Excution dune requte de MJ paramtrable System.out.println("\n\nNow demostrating a prepared statement..."); sqlText = "INSERT INTO Salle VALUES (?,?,?)"; System.out.println("The Statement looks like this: "+sqlText+"\n"); System.out.println("Looping several times filling in the fields...\n"); PreparedStatement ps = db prepareStatement(sqlText); PreparedStatement ps = db.prepareStatement(sqlText); // Excution dune requte paramtre String [] NumBatiment = {"A", "B", "C", "P", "D"}; String [] NumSalle = {"208", "026", "405", "340", "120"}; int lenNB = NumBatiment.length; for (int i=0, c=30 ; (i<lenNB) && (c<35) ;c++,i++) { System.out.println(i+" " + NumBatiment[i]+ " " + NumSalle[i]+ "...\n"); ps.setString(1,NumBatiment[i]); //Affectation de la colonne 1(Batiment) MaudeManouvrier - Univ. Paris Dauphine 75 p g( , [ ]) ( ) ps.setString(2,NumSalle[i]);; // Affectation de la colonne 2(Numero_Salle) ps.setInt(3,c); //Affectation de la colonne 3(Capacite) ps.executeUpdate(); } db.commit(); ps.close(); 18 TP JBDC/DAO (6/10) Classe de connexion public class ConfigConnection { public static Connection getConnection(String nomFichierProp) throws IOException, ClassNotFoundException, SQLException { Properties props = new Properties(); URL urlFichierProp = ConfigConnection.class.getResource(nomFichierProp); B ff dI tSt bi ll BufferedInputStream bis = null; try { bis = new BufferedInputStream(urlFichierProp.openStream()); props.load(bis); String driver = props.getProperty("driver"); String url = props.getProperty("url"); String utilisateur = props.getProperty("utilisateur"); String mdp = props.getProperty("mdp"); Class.forName(driver); MaudeManouvrier - Univ. Paris Dauphine 76 return DriverManager.getConnection(url, utilisateur, mdp); } finally { if (bis != null) { bis.close(); } } } TP JBDC/DAO (7/10) Utilisation de la classe de Connexion String username = argv[0]; String password = argv[1]; String fichierProp = argv[2]; String fichierProp = argv[2]; System.out.println("Username=" +username + " Passwd="+password+" fichierProp="+fichierProp+"\n"); db = ConfigConnection.getConnection(fichierProp,username,password); MaudeManouvrier - Univ. Paris Dauphine 77 19 TP JBDC/DAO (8/10) Exemple de classe type Active Record public class Departement { private int id; private String nom; private String nom; private boolean _builtFromDB; private static String _query = "SELECT * FROM Departement"; public Departement() { _builtFromDB=false; } public Departement(ResultSet rs) throws SQLException { MaudeManouvrier - Univ. Paris Dauphine 78 public Departement(ResultSet rs) throws SQLException { id = rs.getInt("Departement_ID"); nom = rs.getString("Nom_Departement"); _builtFromDB = true; } TP JBDC/DAO (9/10) Exemple de classe type Active Record (suite) public void save(Connection cx) throws SQLException { Statement s = cx.createStatement(); if(_builtFromDB) { System.out.println("Executing this command: "+_update()+"\n"); s.executeUpdate(_update()); } else { System.out.println("Executing this command: "+_insert()+"\n"); s.executeUpdate(_insert()); _builtFromDB=true; // Pour rcuperer la cl gnre sous PostgreSQL MaudeManouvrier - Univ. Paris Dauphine 79 ResultSet rset =s.executeQuery("SELECT last_value FROM departement_departement_id_seq"); if (rset.next()) { id = rset.getInt(1); } } } 20 TP JBDC/DAO (10/10) Exemple de classe type Active Record (suite) public void delete(Connection cx) throws SQLException { Statement s = cx.createStatement(); if(_builtFromDB) { System out println("Executing this command: "+ delete()+"\n"); System.out.println( Executing this command: +_delete()+ \n ); s.executeUpdate(_delete()); } else System.out.println("Objet non persistant!"); } Exemple dutilisation de la classe : MaudeManouvrier - Univ. Paris Dauphine 80 // Insertion d'un nouveau dpartement Departement d = new Departement("DEP"); d.save(_cx); _cx.commit(); System.out.println("Dpartement cr et persistant : " + d.toString());