17 Relationnel-objet
17.1 Type définis par l'utilisateur (UDT)
SQL:1999 CREATE TYPE
– colonne d'une table ordinaire,
– attribut d'un autre type,
– type d'objet d'une table d'objets
Script Oracle
17.1.1 Traduction d'une classe
d'objets UML persistante par un type et une TABLE d'objets
CREATE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20)
)
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution TypeDonnéesAnnée, éditeur REF EditeurType )
CREATE TABLE Editeur OF EditeurType (PRIMARY KEY(nomEditeur))
CREATE TABLE Livre OF LivreType (PRIMARY KEY(ISBN),
CONSTRAINT annéeSup0 CHECK(annéeParution.valeurAnnée > 0), CONSTRAINT referenceTableEditeur éditeur SCOPE IS Editeur)
Editeur {UNIQUE: nomEditeur}
nomEditeur : String ville : String
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée 1..*
1 1..*
1
17.1.2 Type de valeurs d'un attribut ou colonne
CREATE TYPE TypeDonnéesAnnée AS OBJECT (valeurAnnée INTEGER)
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution TypeDonnéesAnnée, éditeur REF EditeurType
)
CREATE TABLE Livre OF LivreType (PRIMARY KEY(ISBN),
CONSTRAINT annéeSup0 CHECK(annéeParution.valeurAnnée > 0), CONSTRAINT referenceTableEditeur éditeur SCOPE IS Editeur)
TypeDonnéesAnnée {Integer > 0 }
<<datatype>>
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée
17.1.3 Traduction d'une association un à plusieurs UML par référence simple (REF)
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution DomaineAnnée,
éditeur REF EditeurType, )
Editeur
{UNIQUE: nomEditeur}
nomEditeur : String ville : String
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée
1 1..* 1..*
1
17.1.4 Contrainte SCOPE IS
CREATE TABLE Livre OF LivreType (PRIMARY KEY(ISBN),
CONSTRAINT annéeSup0 CHECK(annéeParution.valeurAnnée > 0), CONSTRAINT referenceTableEditeur éditeur SCOPE IS Editeur)
Editeur {UNIQUE: nomEditeur}
nomEditeur : String ville : String
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée
1 1..*1..*
1
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution DomaineAnnée,
éditeur REF EditeurType,
)
17.1.5 Indexage pour améliorer la
performance des requêtes utilisant les références
Index sur un attribut REF
Index sur OID (SYSTEM GENERATED)
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution DomaineAnnée,
éditeur REF EditeurType,
) CREATE TABLE Livre OF LivreType (PRIMARY KEY(ISBN),
CONSTRAINT annéeSup0 CHECK(annéeParution.valeurAnnée > 0), CONSTRAINT referenceTableEditeur éditeur SCOPE IS Editeur) CREATE INDEX indexEditeurLivre ON Livre(éditeur)
CREATE TABLE Editeur OF EditeurType (PRIMARY KEY(nomEditeur))
OIDINDEX indexOidEditeur
17.1.6 Références inverses
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution TypeDonnéesAnnée, éditeur REF EditeurType )
CREATE TYPE LivreRefType AS OBJECT (livreRef REF LivreType)
CREATE TYPE tableRefLivresType AS TABLE OF LivreRefType
CREATE OR REPLACE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20),
lesLivres tableRefLivresType )
CREATE TABLE Editeur OF EditeurType (PRIMARY KEY(nomEditeur))
NESTED TABLE lesLivres STORE AS tableLesLivres
Editeur {UNIQUE: nomEditeur}
nomEditeur : String ville : String
Livre {UNIQUE: ISBN}
ISBN : String titre : String
annéeParution : TypeDonnéesAnnée 1..*
1 1..*
1
17.1.8 Représentation d'un type de données complexe ou d'une
composition UML par un UDT
Membre {UNIQUE : noMembre}
noMembre : Integer nom : String prénom : String
adresse : typeDonnéesAdresse
typeDonnéesAdresse numéroCivique : Integer numéroAppartement : Integer nomRue : String
nomVille : String nomProvince : String nomPays : String codePostal : String
<<datatype>>
CREATE TYPE TypeDonnéesAdresse AS OBJECT (noCivique INTEGER,
numéroAppartement INTEGER,
nomRue VARCHAR(20),
nomVille VARCHAR(20), nomProvince VARCHAR(20), nomPays VARCHAR(20), codePostal VARCHAR(10) )
CREATE TYPE MembreType AS OBJECT (noMembre INTEGER,
nom VARCHAR(20),
prénom VARCHAR(20),
adresse typeDonnéesAdresse
Traduction du rôle * d ’une composition par NESTED TABLE (non approprié ici)
CREATE TYPE tableLivresType AS TABLE OF LivreType
CREATE OR REPLACE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20),
lesLivres tableLivresType )
CREATE TABLE Editeur OF EditeurType (PRIMARY KEY(nomEditeur))
NESTED TABLE lesLivres STORE AS tableLesLivres
Stockage à part
VARRAY Oracle (stockage interne à la table)
CREATE TYPE varrayLivresType AS VARRAY(10) OF LivreType
CREATE OR REPLACE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20),
lesLivres varrayLivresType
)
17.1.9 Définition de méthodes
CREATE OR REPLACE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20),
MEMBER FUNCTION nbLivres RETURN NUMBER,
PRAGMA RESTRICT_REFERENCES(nbLivres,WNDS,WNPS) )
CREATE OR REPLACE TYPE BODY EditeurType AS MEMBER FUNCTION nbLivres RETURN NUMBER IS nb NUMBER;
BEGIN
SELECT COUNT(*) INTO nb FROM Livre l
WHERE l.éditeur.nomEditeur = SELF.nomEditeur;
RETURN nb;
END nbLivres;
END;
SELECT e.nbLivres() FROM Editeur e
WHERE e.nomEditeur = 'XXX'
17.1.10 Héritage de types
CREATE TYPE PersonneType AS OBJECT (nom VARCHAR(10),
prénom VARCHAR(10)) NOT FINAL
CREATE TYPE UtilisateurType UNDER PersonneType (idUtilisateur VARCHAR(10),
motPasse VARCHAR(10),
catégorieUtilisateur VARCHAR(14))
Personne nom : String prénom : String
Utilisateur {UNIQUE :idUtilisateur}
idUtilisateur : String motPasse : String
17.2 Extensions au langage de manipulation de données SQL
Expression de chemin
SELECT m.nom, m.adresse.nomRue FROM Membre m
WHERE m.adresse.nomVille = 'Montréal'
CREATE TYPE TypeDonnéesAdresse AS OBJECT (noCivique INTEGER,
numéroAppartement INTEGER,
nomRue VARCHAR(20),
nomVille VARCHAR(20), nomProvince VARCHAR(20),
nomPays VARCHAR(20),
codePostal VARCHAR(10) )
CREATE TYPE MembreType AS OBJECT (noMembre INTEGER,
nom VARCHAR(20),
prénom VARCHAR(20),
adresse typeDonnéesAdresse )
CREATE TABLE Membre OF MembreType (PRIMARY KEY(noMembre))
17.2.2 Cheminement par références
SELECT l.éditeur.nomEditeur, l.ISBN FROM Livre l
WHERE l.éditeur.ville = 'Paris'
CREATE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20)
)
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution TypeDonnéesAnnée, éditeur REF EditeurType )
CREATE TABLE Editeur OF EditeurType (PRIMARY KEY(nomEditeur))
CREATE TABLE Livre OF LivreType (PRIMARY KEY(ISBN),
CONSTRAINT annéeSup0 CHECK(annéeParution.valeurAnnée > 0), CONSTRAINT referenceTableEditeur éditeur SCOPE IS Editeur)
17.2.3 Accès à une table enchâssée par l'opérateur d'aplatissement (THE)
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution TypeDonnéesAnnée, éditeur REF EditeurType )
CREATE TYPE LivreRefType AS OBJECT (livreRef REF LivreType)
CREATE TYPE tableRefLivresType AS TABLE OF LivreRefType
CREATE OR REPLACE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20),
lesLivres tableRefLivresType )
CREATE TABLE Editeur OF EditeurType (PRIMARY KEY(nomEditeur))
NESTED TABLE lesLivres STORE AS tableLesLivres SELECT livres.livreRef.ISBN, livres.livreRef.titre
FROM THE
(SELECT e.lesLivres FROM Editeur e WHERE nomEditeur = 'Addison-Wesley') livres
17.2.4 Insertion et constructeur d'objet
CREATE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20),
)
CREATE TABLE Editeur OF EditeurType (PRIMARY KEY(nomEditeur))
INSERT INTO Editeur VALUES
('Loze-Dion', 'Longueuil') INSERT INTO Editeur VALUES
(EditeurType('Loze-Dion', 'Longueuil'))
TYPE dans une colonne
INSERT INTO Membre VALUES
(10,'Tremblay','Jean',TypeDonnéesAdresse(100,2,
'Ste-Catherine','Montréal','Québec','Canada','H3C 3P8'))
CREATE TYPE TypeDonnéesAdresse AS OBJECT (noCivique INTEGER,
numéroAppartement INTEGER,
nomRue VARCHAR(20),
nomVille VARCHAR(20), nomProvince VARCHAR(20),
nomPays VARCHAR(20),
codePostal VARCHAR(10) )
CREATE TYPE MembreType AS OBJECT (noMembre INTEGER,
nom VARCHAR(20),
prénom VARCHAR(20),
adresse typeDonnéesAdresse )
CREATE TABLE Membre OF MembreType (PRIMARY KEY(noMembre))
Colonne REF
CREATE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20)
)
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution TypeDonnéesAnnée, éditeur REF EditeurType )
CREATE TABLE Editeur OF EditeurType (PRIMARY KEY(nomEditeur))
CREATE TABLE Livre OF LivreType (PRIMARY KEY(ISBN),
CONSTRAINT annéeSup0 CHECK(annéeParution.valeurAnnée > 0), CONSTRAINT referenceTableEditeur éditeur SCOPE IS Editeur)
INSERT INTO Livre
SELECT '0-201-12227-8', 'Automatic Text Processing', typeDonnéesAnnée(1989),REF(e)
FROM Editeur e WHERE nomEditeur = 'Addison-Wesley'
Insertion dans un NESTED TABLE
CREATE TYPE LivreType AS OBJECT
(ISBN CHAR(13),
titre VARCHAR(50),
annéeParution TypeDonnéesAnnée, éditeur REF EditeurType )
CREATE TYPE LivreRefType AS OBJECT (livreRef REF LivreType)
CREATE TYPE tableRefLivresType AS TABLE OF LivreRefType
CREATE OR REPLACE TYPE EditeurType AS OBJECT (nomEditeur VARCHAR(20),
ville VARCHAR(20),
lesLivres tableRefLivresType )
CREATE TABLE Editeur OF EditeurType (PRIMARY KEY(nomEditeur))
NESTED TABLE lesLivres STORE AS tableLesLivres
INSERT INTO Editeur VALUES
('Loze-Dion', 'Longueuil',tableRefLivresType()) INSERT INTO Livre
SELECT '0-201-12227-8', 'Automatic Text Processing', TypeDonnéesAnnée(1989), REF(e)
FROM Editeur e WHERE nomEditeur = 'Addison-Wesley' INSERT INTO THE
(SELECT e.lesLivres FROM Editeur e WHERE e.nomEditeur = 'Addison-Wesley') SELECT REF(l) FROM Livre l
WHERE l.ISBN = '0-201-12227-8'
17.3 Accès aux extensions objets en Java
Créer une classe Java pour un UDT
– Typage faible : java.sql.Struct
– Typage fort
classe Java implements SQLData
Créer un UDT à partir d ’une classe Java
– SQLJ (partie 2)
17.3.1 Typage faible par java.sql.Struct
// Recherche de la référence au LivreType ISBN = '0-201-12227-8'
PreparedStatement unPreparedStatement = uneConnection.prepareStatement ("SELECT REF(l) AS refLivre FROM Livre l WHERE l.ISBN = '0-201-12227-8'");
ResultSet unResultSet = unPreparedStatement.executeQuery();
if (unResultSet.next()){
// Conversion de la référence à l'UDT LivreType sous forme d'un objet Java REF REF ref = (REF) unResultSet.getObject(1);
// Extraire l'objet LivreType référencé sous forme d'un STRUCT STRUCT unLivreSTRUCT = (STRUCT) ref.getValue();
// Recherche des attributs du UDT LivreType sous forme d'un tableau d'objets Object attributsDeLivre[] = unLivreSTRUCT.getAttributes();
// Cast des attributs selon leur type
System.out.println("ISBN :"+(String)attributsDeLivre[0]); // ISBN CHAR(13) System.out.println("titre :"+(String)attributsDeLivre[1]); // titre VARCHAR(50)
17.3.2 Typage fort et conversion de type automatique avec SQLdata
public class LivreTypePourUDT implements SQLData {// nomUDT contient le nom du UDT qui correspond à la classe private String nomUDT = "GODIN.LIVRETYPE";
protected String ISBN;
protected String titre;
protected Typedonnéesannée annéeParution;
protected java.sql.Ref éditeur;
public LivreTypePourUDT(){}
// Lecteurs et modifieurs
public String getIsbn(){ return ISBN; }
public void setIsbn(String isbn){ this.ISBN = isbn; }
…
// public int getLengthTitre(){ return titre.length();}
public String getTitreEnMinuscules(){return titre.toLowerCase();}
// Méthodes de l'interface SQLdata à implémenter // Retourne le UDT SQL qui correspond à la classe Java
public String getSQLTypeName() throws SQLException { return nomUDT;}
public void readSQL(SQLInput stream, String type) throws SQLException{
setIsbn(stream.readString());
setTitre(stream.readString());
setAnnéeparution((Typedonnéesannée)stream.readObject());
setÉditeur(stream.readRef());
}
public void writeSQL(SQLOutput stream) throws SQLException{
stream.writeString(getIsbn());
stream.writeString(getTitre());
CAST du REF UDT en objet Java
// Recherche de la référence au LivreType ISBN = '0-201-12227-8'
PreparedStatement unPreparedStatement = uneConnection.prepareStatement ("SELECT REF(l) AS refLivre FROM Livre l WHERE l.ISBN = '0-201-12227-8'");
ResultSet unResultSet = unPreparedStatement.executeQuery();
//Créer un type map qui associe le UDT à la classe SQLdata java.util.Map typeMap = uneConnection.getTypeMap();
typeMap.put("LIVRETYPE",Class.forName("LivreTypePourUDT"));
typeMap.put("TYPEDONNÉESANNÉE",Class.forName("Typedonnéesannée"));
typeMap.put("EDITEURTYPE",Class.forName("EditeurTypePourUDT"));
if (unResultSet.next()){
// Conversion de la référence à l'UDT LivreType sous forme d'un objet Java REF REF ref = (REF) unResultSet.getObject(1);
LivreTypePourUDT unLivreType = (LivreTypePourUDT)ref.getValue();
System.out.println("ISBN :"+unLivreType.getIsbn()); // ISBN CHAR(13)
System.out.println("titre :"+unLivreType.getTitre()); // titre VARCHAR(50)
Pour le pilote JDBC
17.3.3 Objet SQLJ : partie 2 de la norme SQLJ
Déployer les classes Java TypeDonnéesAnnée et LivreType au niveau du serveur BD
– Outil loadjava d ’Oracle