Mapping objet-relationnel
Un mapping objet-relationnel (en anglais object-relational mapping ou ORM) est un type de programme informatique qui se place en interface entre un programme applicatif et une base de données relationnelle pour simuler une base de données orientée objet. Ce programme définit des correspondances entre les schémas de la base de données et les classes du programme applicatif. On pourrait le désigner par là « comme une couche d'abstraction entre le monde objet et monde relationnel ». Du fait de sa fonction, on retrouve ce type de programme dans un grand nombre de frameworks sous la forme de composant ORM qui a été soit développé, soit intégré depuis une solution externe.
Explication du problĂšme
L'utilisation de la programmation orientée objet avec une base de données relationnelle nécessite de convertir les données relationnelles en objets et vice-versa. Ceci conduit à programmer cette conversion pour chaque objet et donc à dupliquer énormément de code similaire.
Illustration de code Java qui utilise l'API JDBC sans ORM pour récupérer les données relationnelles d'un client (customer en anglais) afin de les transformer en un objet Java :
public Customer loadCustomer(long customerId, Connection connection) {
if (0 == customerId || connection == null) {
return null;
}
PreparedStatement statement = null;
try {
// prĂ©paration de la requĂȘte Ă la base de donnĂ©es
statement = connection.prepareStatement(
" SELECT CUSTOMER_ID, CUSTOMER_NAME, CUSTOMER_ADDRESS "
+ " FROM CUSTOMER WHERE CUSTOMER_ID = ? ");
statement.setLong(1, customerId);
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
// transformation des données relationnelles en objet "Customer"
Customer customer = new Customer();
int index = 1;
customer.setCustomerId(resultSet.getLong(index++));
customer.setCustomerName(resultSet.getString(index++));
customer.setCustomerAddress(resultSet.getString(index++));
return customer;
}
} catch (final Exception e) {
log.info("", e);
} finally {
// nettoyage
if (statement != null) {
try {
statement.close();
} catch (final SQLException e) {
log.info("", e);
}
}
}
return null;
}
Un code source trĂšs similaire sera Ă saisir pour rĂ©cupĂ©rer les informations des autres tables et les transformer en objets. Les parties du code qui changent sont : le SQL, l'affectation des paramĂštres sur l'objet PreparedStatement et la rĂ©cupĂ©ration des rĂ©sultats et leur affectation sur l'objet. La structure gĂ©nĂ©rale du code reste toujours la mĂȘme.
En fait, le code permettant de réaliser toutes les opérations de CRUD (création, lecture, mise à jour, suppression) se ressemble énormément d'une table à l'autre et d'un objet à l'autre.
Les frameworks de mapping objet-relationnel permettent d'éliminer la duplication de code dans les opérations CRUD.
Principe de résolution
Le mapping objet-relationnel consiste à déclarer une association entre une (ou plusieurs) classes et une table, et chaque attribut de la classe avec un champ de la table associée. Par exemple, la classe Customer sera associée à la table CUSTOMER, et les attributs associés comme suit :
- Customer â CUSTOMER :
- Customer.customerId est associée avec CUSTOMER.CUSTOMER_ID
- Customer.customerName est associée avec CUSTOMER.CUSTOMER_NAME
- Customer.customerAddress est associée avec CUSTOMER.CUSTOMER_ADDRESS
Un fichier texte peut alors ĂȘtre crĂ©Ă© pour dĂ©clarer et dĂ©crire en bloc de telles mises en correspondance sur un ensemble de classes et tables du modĂšle. Lorsque le langage le permet (Java par exemple), il est mĂȘme possible d'utiliser l'introspection pour rĂ©cupĂ©rer les informations sur les attributs lors de l'exĂ©cution (type, valeur, etc.) et pouvoir construire dynamiquement les requĂȘtes SQL de type CRUD. Des mĂ©canismes similaires existent pour les autres langages disposant de frameworks de mapping objet-relationnel.
Le rĂ©sultat finit par simuler une base de donnĂ©es "objet" "virtuelle", qui peut ĂȘtre utilisĂ©e au sein du langage de programmation sans rĂ©fĂ©rencer directement le SGBD sous-jacent.
ProblÚme des cardinalités
Habituellement les tĂąches de gestion des donnĂ©es dans un programme incluant un ORM sont exĂ©cutĂ©es en contrĂŽlant des objets qui sont gĂ©nĂ©ralement des valeurs non scalaires. Par exemple, considĂ©rons une entrĂ©e d'agenda qui d'une part rĂ©pertorie une personne seule avec des anniversaires, et liste d'autre part zĂ©ro ou plusieurs anniversaires. Cela pourrait alors ĂȘtre modĂ©lisĂ© sous la forme d'un objet "Personne" comprenant lui-mĂȘme des objets correspondants aux donnĂ©es qui constituent l'entrĂ©e d'agenda. Par exemple, l'objet "Personne" inclurait un ou plusieurs objets "Anniversaire", eux-mĂȘmes pouvant d'ailleurs contenir Ă leur tour des objets "Personne". Les anniversaires peuvent alors ĂȘtre traitĂ©s comme des valeurs/entitĂ©s individuelles par le langage de programmation, diffĂ©renciĂ©s des entrĂ©es personnes. De plus, diffĂ©rentes mĂ©thodes peuvent ĂȘtre liĂ©es aux objets.
Cependant un problÚme se pose : alors qu'un langage de programmation va permettre typiquement d'imbriquer des listes d'objets dans un objet, de nombreux SGBD populaires sont conçus quant à eux pour stocker et manipuler des valeurs scalaires, tels que les entiers et les chaßnes structurées dans des tableaux normalisés. Un exemple typique d'un tel produit systÚme serait un SGBD Structured Query Language (SQL).
Le programmeur doit alors faire un choix :
- il peut convertir les valeurs objets de son programme en groupes de valeurs simples pour le stockage dans la base de données (sérialisation des données), pour les re-convertir en objets lors de leur récupération ultérieure (désérialisation des données),
- ou bien décider de n'utiliser que des valeurs scalaires dans le programme, ce qui peut avoir un trÚs fort impact sur la structure du programme.
Les ORM sont utilisĂ©s pour mettre en Ćuvre la premiĂšre solution.
Avantages et inconvénients
Il y a des avantages et des inconvénients à l'utilisation d'ORM.
L'un des avantages est que cela rĂ©duit la quantitĂ© de code qui doit ĂȘtre Ă©crit et permet une homogĂ©nĂ©itĂ© avec le reste du code pour les langages orientĂ©s objets.
Cependant, les ORM induisent une couche logicielle supplémentaire, ce qui peut nuire aux performances, et bien entendu à la maintenabilité. Par ailleurs, certains outils ORM ont historiquement montré des limites lors de la suppression de données en bloc. En outre, une base de données mal conçue peut induire une forte dépendance à un systÚme ORM, et réciproquement.
Le mapping objet-relationnel est toutefois considéré en 2018 comme une méthode de programmation viable pour la traduction des données entre les systÚmes de bases de données relationnelles et des langages de programmation orientés objet.
Frameworks de mapping objet-relationnel
Il existe de nombreux outils d'ORM payants, gratuits ou mĂȘme en licence libre.
Voici quelques frameworks de mapping objet-relationnel :
- Java
- Java Persistence API
- Hibernate
- Spring Data
- Java Data Objects
- Apache Cayenne
- OJB - Object Relational Bridge
- Apache Torque
- SimpleORM
- iBATIS
- Avaje Ebean
- Grails
- AJO
- .Net
- CodeFluent Entities
- Entity Framework[1]
- NHibernate
- Linq To SQL (.Net Framework 3.5)
- iBATIS
- Euss (Evaluant Universal Storage Services)
- MyGeneration/dOOdads
- LayerCake Generator (.NET Framework 4.5)
- Ruby
- Active record
- RBatis, portage de iBATIS en Ruby pour Ruby on Rails
- Sequel
- DataMapper
- PHP 5
- RedBean
- Doctrine
- Pdomap
- Phpmyobject
- CakePhp
- Propel
- FoxOrm
- AgileToolKit
- Syrius
- Fuelphp
- Eloquent
- Python
- SQLAlchemy
- Peewee
- SQLObject
- Django
- Node.js
- Delphi
- Synopse mORMot framework
- TMS Software's TMS Aurelius - commercial.
- Delphi ORM - open source
- Perl
- DBIx::Class
- Rose::DB::Object
- Class::DBI
- Rust
- Diesel
- RustOrm
- Elixir
- Ecto
- Scala
- Slick
Références
- « Vue dâensemble dâEntity Framework », sur docs.microsoft.com, (consultĂ© le )