{"id":37082,"date":"2017-03-28T10:11:04","date_gmt":"2017-03-28T08:11:04","guid":{"rendered":"\/blog\/?p=12540"},"modified":"2023-07-05T23:57:20","modified_gmt":"2023-07-05T21:57:20","slug":"developper-avec-jpa-et-exo-platform","status":"publish","type":"post","link":"https:\/\/www.exoplatform.com\/blog\/fr\/developper-avec-jpa-et-exo-platform\/","title":{"rendered":"Developper avec JPA et eXo Platform"},"content":{"rendered":"<p>Depuis la version 4.3, eXo Platform fournit une <strong>int\u00e9gration native avec JPA<\/strong> (Java Persistence API).<\/p>\n<p><strong>JPA <\/strong>est une sp\u00e9cification d\u2019<strong>API Java<\/strong> pour la gestion de donn\u00e9es relationnelles dans les applications Java. Cette API permet de lier une classe Java (appel\u00e9e Entit\u00e9) avec une table de base de donn\u00e9es relationnelles \u00e0 l\u2019aide d\u2019annotations Java ou de configuration XML.<\/p>\n<p><!--more--><\/p>\n<p>La sp\u00e9cification d\u00e9finit aussi une API EntityManager pour g\u00e9rer le traitement des requ\u00eates et des transactions sur les objets Java sur la base de donn\u00e9es.<\/p>\n<p><a href=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA.png\"><img decoding=\"async\" loading=\"lazy\" class=\"size-full wp-image-12542 aligncenter\" src=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA.png\" alt=\"Developper avec JPA et eXo Platform\" width=\"1035\" height=\"407\" srcset=\"https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA.png 1035w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA-300x118.png 300w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA-1024x403.png 1024w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA-768x302.png 768w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA-720x283.png 720w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA-500x197.png 500w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA-360x142.png 360w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA-200x79.png 200w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA-100x39.png 100w, https:\/\/www.exoplatform.com\/blog\/wp-content\/uploads\/2017\/03\/JPA-70x28.png 70w\" sizes=\"(max-width: 1035px) 100vw, 1035px\" \/><\/a><\/p>\n<p>Pour avoir plus d\u2019informations sur JPA, n\u2019h\u00e9sitez pas \u00e0 parcourir <a href=\"https:\/\/docs.oracle.com\/javaee\/7\/tutorial\/partpersist.htm\" target=\"_blank\" rel=\"noopener\">la documentation officielle<\/a>.<\/p>\n<p>L\u2019int\u00e9gration faite dans eXo Platform nous a permis de <a href=\"https:\/\/www.exoplatform.com\/blog\/why-are-we-moving-away-from-jcr\/\">d\u00e9marrer notre transition vers un nouveau mod\u00e8le de donn\u00e9es<\/a> et de donner aux d\u00e9veloppeurs la capacit\u00e9 de cr\u00e9er leurs propres applications bas\u00e9es sur JPA.<\/p>\n<p>Cet article d\u00e9crit cette int\u00e9gration et explique comment d\u00e9velopper des applications en utilisant JPA dans eXo Platform.<\/p>\n<h2>Integration JPA<\/h2>\n<p><a href=\"http:\/\/hibernate.org\/orm\/\" target=\"_blank\" rel=\"noopener\">Hibernate<\/a> est l\u2019impl\u00e9mentation JPA utilis\u00e9e, c\u2019est l\u2019impl\u00e9mentation de r\u00e9f\u00e9rence de la sp\u00e9cification. Depuis eXo Platform 4.3 il est possible de \u201cmapper\u201d facilement des entit\u00e9s (classes) Java avec JPA\/Hibernate.<\/p>\n<p>Nous avons tout pr\u00e9par\u00e9 pour vous : la datasource, la persistence unit, des annotations pour les entit\u00e9s et un DAO g\u00e9n\u00e9rique.<\/p>\n<h3>Datasource<\/h3>\n<p>Une nouvelle datasource est disponible par d\u00e9faut dans eXo Platform, appel\u00e9e \u201cexo-jpa_portal\u201d (le nom peut \u00eatre chang\u00e9 \u00e0 l\u2019aide de la propri\u00e9t\u00e9 \u201cexo.jpa.datasource.name\u201d dans <a href=\"https:\/\/docs.exoplatform.org\/\" target=\"_blank\" rel=\"noopener\">le fichier exo.properties<\/a>).<\/p>\n<p>Cette datasource est utilis\u00e9e pour toutes les op\u00e9rations qui utilisent la persistence unit eXo.<\/p>\n<h3>Persistence unit et entity manager<\/h3>\n<p>Toutes les op\u00e9rations JPA doivent utiliser une persistence unit et un entity manager pour interagir avec la base de donn\u00e9es. La persistence unit d\u00e9finie la datasource \u00e0 utiliser, les entit\u00e9s \u00e0 g\u00e9rer et un ensemble d\u2019autres param\u00e8tres de configuration.<\/p>\n<p>Nous avons ajout\u00e9 une persistence unit par d\u00e9faut dans eXo Platform, appel\u00e9 <strong>exo-pu<\/strong>, qui utilise la datasource par d\u00e9faut exo-jpa_portal, et qui ne d\u00e9clare aucune entit\u00e9 :<\/p>\n<p><i>&lt;persistence xmlns=&#8221;http:\/\/java.sun.com\/xml\/ns\/persistence&#8221;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/i> <i>xmlns:xsi=&#8221;http:\/\/www.w3.org\/2001\/XMLSchema-instance&#8221;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/i> <i>xsi:schemaLocation=&#8221;http:\/\/java.sun.com\/xml\/ns\/persistence http:\/\/java.sun.com\/xml\/ns\/persistence\/persistence_2_0.xsd&#8221;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/i> <i>version=&#8221;2.0&#8243;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;persistence-unit name=&#8221;exo-pu&#8221; transaction-type=&#8221;RESOURCE_LOCAL&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;provider&gt;org.hibernate.ejb.HibernatePersistence&lt;\/provider&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;non-jta-data-source&gt;java:\/comp\/env\/exo-jpa_portal&lt;\/non-jta-data-source&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;properties&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;property name=&#8221;persistenceUnitName&#8221; value=&#8221;exo-pu&#8221;&gt;&lt;\/property&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/properties&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;\/persistence-unit&gt;<\/i><\/p>\n<p><i>&lt;\/persistence&gt;<\/i><\/p>\n<p>La configuration de cette persistence unit peut \u00eatre modifi\u00e9 facilement en d\u00e9finissant le param\u00e8tre dans <a href=\"https:\/\/docs.exoplatform.org\/\" target=\"_blank\" rel=\"noopener\">le fichier exo.properties<\/a>, pr\u00e9fix\u00e9 par \u201cexo.jpa.\u201d.<\/p>\n<p>Par exemple, pour demander \u00e0 Hibernate de tracer toutes les requ\u00eates SQL, il suffit d\u2019ajouter la ligne suivante :<\/p>\n<p><i>exo.jpa.hibernate.show_sql=true<\/i><\/p>\n<h3>Entiti\u00e9s<\/h3>\n<p>eXo Platform fournit une annotation pour ajouter une entit\u00e9 JPA dans la persistence unit (exo-pu): <strong>@ExoEntity<\/strong>. Voici un example :<\/p>\n<p>&nbsp;<\/p>\n<p><i>@Entity(name = &#8220;TaskTask&#8221;)<\/i><\/p>\n<p><i>@ExoEntity<\/i><\/p>\n<p><i>public class Task {<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0@Id<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0@SequenceGenerator(name=&#8221;SEQ_TASK_TASKS_TASK_ID&#8221;, sequenceName=&#8221;SEQ_TASK_TASKS_TASK_ID&#8221;)<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0@GeneratedValue(strategy=GenerationType.AUTO, generator=&#8221;SEQ_TASK_TASKS_TASK_ID&#8221;)<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0@Column(name = &#8220;TASK_ID&#8221;)<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0private long \u00a0\u00a0\u00a0<\/i> <i>id;<\/i><\/p>\n<p>&nbsp;<\/p>\n<p><i> \u00a0\u00a0\u00a0private String \u00a0<\/i> <i>title;<\/i><\/p>\n<p>&nbsp;<\/p>\n<p><i> \u00a0\u00a0\u00a0private String \u00a0<\/i> <i>description;<\/i><\/p>\n<p>&nbsp;<\/p>\n<p><i> \u00a0\u00a0\u00a0&#8230;<\/i><\/p>\n<p><i>}<\/i><\/p>\n<p>Ceci est un extrait de l\u2019entit\u00e9 task. Comme vous pouvez le voir, il s\u2019agit d\u2019une entit\u00e9 JPA standard (annot\u00e9 avec @Entity). La seule diff\u00e9rence est l\u2019ajout de l\u2019annotation @ExoEntity.<\/p>\n<p>Ajouter cette annotation et mettre cette classe dans le classpath ajoute automatiquement cette entit\u00e9 dans la persistence unit eXo.<\/p>\n<h3>Transactions<\/h3>\n<p>@ExoEntity n\u2019est pas la seule annotation fournie par eXo Platform; nous avons \u00e9galement ajout\u00e9 une annotation pour d\u00e9finir une m\u00e9thode transactionnelle : @ExoTransactional.<\/p>\n<p>Apposer cette annotation sur une m\u00e9thode permet d\u2019utiliser automatiquement l\u2019entity manager pour d\u00e9marrer une transaction et la fermer, ou d\u2019utiliser une transaction existante si elle a d\u00e9j\u00e0 \u00e9t\u00e9 ouverte.<\/p>\n<p><i>@ExoTransactional<\/i><\/p>\n<p><i>public Task createTask(Task task) {<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&#8230;<\/i><\/p>\n<p><i>}<\/i><\/p>\n<p>Le plugin Maven JCabi doit \u00eatre activ\u00e9 pour le bon fonctionnement de cette annotation. Pour cela, 2 fa\u00e7ons de proc\u00e9der existent :<\/p>\n<ul>\n<li style=\"font-weight: 400;\">Utiliser le POM parent eXo addons en tant que POM (Project Object Model) parent de votre projet, comme dans <a href=\"https:\/\/github.com\/exoplatform\/task\/blob\/1.0.0\/pom.xml#L24-L28\" target=\"_blank\" rel=\"noopener\">le projet Task<\/a> :<\/li>\n<\/ul>\n<p><i>&lt;parent&gt;<\/i><i><br \/>\n<\/i><i> \u00a0\u00a0\u00a0&lt;artifactId&gt;addons-parent-pom&lt;\/artifactId&gt;<\/i><i><br \/>\n<\/i><i> \u00a0\u00a0\u00a0&lt;groupId&gt;org.exoplatform.addons&lt;\/groupId&gt;<\/i><i><br \/>\n<\/i><i> \u00a0\u00a0\u00a0&lt;version&gt;6&lt;\/version&gt;<\/i><i><br \/>\n<\/i><i>&lt;\/parent&gt;<\/i><\/p>\n<p>et d\u00e9clarer le plugin JCabi dans le module qui utilise @ExoTransactional :<\/p>\n<p><i>&lt;build&gt;<\/i><i><br \/>\n<\/i><i> \u00a0\u00a0\u00a0&lt;plugins&gt;<\/i><i><br \/>\n<\/i><i> \u00a0\u00a0\u00a0\u00a0\u00a0&lt;plugin&gt;<\/i><i><br \/>\n<\/i><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;groupId&gt;com.jcabi&lt;\/groupId&gt;<\/i><i><br \/>\n<\/i><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;artifactId&gt;jcabi-maven-plugin&lt;\/artifactId&gt;<\/i><i><br \/>\n<\/i><i> \u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/plugin&gt;<\/i><i><br \/>\n<\/i><i> \u00a0\u00a0\u00a0&lt;\/plugins&gt;<\/i><i><br \/>\n<\/i><i>&lt;\/build&gt;<\/i><\/p>\n<ul>\n<li style=\"font-weight: 400;\">Ajouter le plugin JCabi avec la configuration compl\u00e8te :<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><i>&lt;build&gt;<\/i><\/p>\n<p><i> \u00a0&lt;plugins&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;plugin&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0&lt;groupId&gt;com.jcabi&lt;\/groupId&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0&lt;artifactId&gt;jcabi-maven-plugin&lt;\/artifactId&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0&lt;version&gt;${version.jcabi.plugin}&lt;\/version&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0&lt;executions&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;execution&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;id&gt;weave-classes&lt;\/id&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;phase&gt;process-classes&lt;\/phase&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;goals&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;goal&gt;ajc&lt;\/goal&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/goals&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;configuration&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;classesDirectory&gt;${project.build.outputDirectory}&lt;\/classesDirectory&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/configuration&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/execution&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;execution&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;id&gt;weave-test-classes&lt;\/id&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;phase&gt;process-test-classes&lt;\/phase&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;goals&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;goal&gt;ajc&lt;\/goal&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/goals&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;configuration&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;classesDirectory&gt;${project.build.testOutputDirectory}&lt;\/classesDirectory&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/configuration&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/execution&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/executions&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;\/plugin&gt;<\/i><\/p>\n<p><i> \u00a0&lt;\/plugins&gt;<\/i><\/p>\n<p><i>&lt;\/build&gt;<\/i><\/p>\n<h3>DAO g\u00e9n\u00e9rique<\/h3>\n<p>Afin de rendre la vie des d\u00e9veloppeurs plus simple nous avons \u00e9galement ajout\u00e9 un DAO g\u00e9n\u00e9rique qui d\u00e9finit toutes les op\u00e9rations basiques d\u2019acc\u00e8s aux donn\u00e9es, en utilisant l\u2019entity manager eXo : find, findAll, create, update, delete, &#8230;<\/p>\n<p>xIl suffit de faire h\u00e9riter votre DAO de la classe org.exoplatform.commons.persistence.impl.GenericDAOJPAImpl pour b\u00e9n\u00e9ficier de toutes ces m\u00e9thodes :<\/p>\n<p><i>public class TaskDAOImpl extends GenericDAOJPAImpl&lt;Task, Long&gt; {<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u2026<\/i><\/p>\n<p><i>}<\/i><\/p>\n<h2>Cr\u00e9ez votre mod\u00e8le de donn\u00e9es<\/h2>\n<p>Maintenant que nous avons con\u00e7u notre mod\u00e8le de donn\u00e9es en Java, nous avons besoin de cr\u00e9er la structure des donn\u00e9es dans la base de donn\u00e9es.<\/p>\n<p>Hibernate permet de g\u00e9n\u00e9rer automatiquement la structure des donn\u00e9es \u00e0 partir du mod\u00e8le Java, en se basant sur les annotations JPA et le param\u00e8tre de configuration <a href=\"http:\/\/docs.jboss.org\/hibernate\/orm\/4.2\/manual\/en-US\/html_single\/#configuration-optional\" target=\"_blank\" rel=\"noopener\"><strong>hbm2ddl.auto<\/strong><\/a>.<\/p>\n<p>Cependant, nous pensons que la mod\u00e9lisation des donn\u00e9es dans la base de donn\u00e9es est une phase primordiale dans la conception d\u2019une solution et ne doit pas reposer sur la g\u00e9n\u00e9ration automatique par Hibernate.<\/p>\n<p>Elle doit \u00eatre r\u00e9alis\u00e9e dans un processus d\u00e9di\u00e9, d\u2019un point de vue conception et ex\u00e9cution. Il est important que les d\u00e9veloppeurs ma\u00eetrisent compl\u00e8tement le mod\u00e8le de donn\u00e9es.<\/p>\n<p>eXo Platform int\u00e8gre <a href=\"http:\/\/www.liquibase.org\/\" target=\"_blank\" rel=\"noopener\">Liquibase<\/a>, un outil qui permet d\u2019initialiser et de mettre \u00e0 jour de mani\u00e8re incr\u00e9mentale le mod\u00e8le de donn\u00e9es et les donn\u00e9es.<\/p>\n<p>Son utilisation n\u2019est pas obligatoire pour d\u00e9velopper des applications dans eXo Platform mais elle est grandement recommand\u00e9e puisqu\u2019elle fournit un moyen simple et efficace de g\u00e9rer une base de donn\u00e9es.<\/p>\n<p>C\u2019est ce que nous utilisons pour les donn\u00e9es de la plateforme.<\/p>\n<p>Liquibase utilise des fichiers de changelog pour initialiser et mettre \u00e0 jour la base de donn\u00e9es. Ces fichiers contiennent un ensemble de <strong>change sets<\/strong>.<\/p>\n<p>Chaque change set d\u00e9finit une op\u00e9ration sur la base de donn\u00e9es (cr\u00e9ation d\u2019une table, ajout d\u2019une contrainte, cr\u00e9ation d\u2019un index, ex\u00e9cution d\u2019une requ\u00eate SQL, \u2026). Voici un exemple de changelog (celui de l\u2019application eXo Task) :<\/p>\n<p><i>&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;UTF-8&#8243;?&gt;<\/i><\/p>\n<p><i>&lt;databaseChangeLog<\/i><\/p>\n<p><i>xmlns=&#8221;http:\/\/www.liquibase.org\/xml\/ns\/dbchangelog&#8221;<\/i><\/p>\n<p><i>xmlns:xsi=&#8221;http:\/\/www.w3.org\/2001\/XMLSchema-instance&#8221;<\/i><\/p>\n<p><i>xsi:schemaLocation=&#8221;http:\/\/www.liquibase.org\/xml\/ns\/dbchangelog<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/i> <i>http:\/\/www.liquibase.org\/xml\/ns\/dbchangelog\/dbchangelog-3.3.xsd&#8221;&gt;<\/i><\/p>\n<p>&nbsp;<\/p>\n<p><i>&lt;!&#8211; Managing both DB that use sequences and db that use auto increment &#8211;&gt;<\/i><\/p>\n<p><i>&lt;property name=&#8221;autoIncrement&#8221; value=&#8221;true&#8221; dbms=&#8221;mysql,mssql,h2,sybase,db2,hsqldb&#8221;\/&gt;<\/i><\/p>\n<p><i>&lt;property name=&#8221;autoIncrement&#8221; value=&#8221;false&#8221; dbms=&#8221;oracle,postgresql&#8221;\/&gt;<\/i><\/p>\n<p>&nbsp;<\/p>\n<p><i>&lt;!&#8211; Definition of TASK_PROJECTS table &#8211;&gt;<\/i><\/p>\n<p><i>&lt;changeSet author=&#8221;task&#8221; id=&#8221;1.0.0-1&#8243;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;createTable tableName=&#8221;TASK_PROJECTS&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;column name=&#8221;PROJECT_ID&#8221; type=&#8221;BIGINT&#8221; autoIncrement=&#8221;${autoIncrement}&#8221; startWith=&#8221;1&#8243;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;constraints nullable=&#8221;false&#8221; primaryKey=&#8221;true&#8221; primaryKeyName=&#8221;PK_TASK_PROJECTS&#8221; \/&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/column&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;column name=&#8221;NAME&#8221; type=&#8221;NVARCHAR(50)&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;constraints nullable=&#8221;false&#8221;\/&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/column&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;column name=&#8221;DESCRIPTION&#8221; type=&#8221;NVARCHAR(2000)&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;constraints nullable=&#8221;true&#8221;\/&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/column&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;column name=&#8221;COLOR&#8221; type=&#8221;NVARCHAR(100)&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;constraints nullable=&#8221;true&#8221;\/&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/column&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;column name=&#8221;CALENDAR_INTEGRATED&#8221; type=&#8221;BIT&#8221; defaultValue=&#8221;0&#8243;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;constraints nullable=&#8221;false&#8221;\/&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/column&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;column name=&#8221;DUE_DATE&#8221; type=&#8221;TIMESTAMP&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;constraints nullable=&#8221;true&#8221;\/&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/column&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;column name=&#8221;PARENT_PROJECT_ID&#8221; type=&#8221;BIGINT&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;constraints foreignKeyName=&#8221;FK_TASK_PRJ_TASK_PRJ_01&#8243; references=&#8221;TASK_PROJECTS(PROJECT_ID)&#8221; nullable=&#8221;true&#8221;\/&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/column&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;\/createTable&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;modifySql dbms=&#8221;mysql&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;append value=&#8221; ENGINE=INNODB CHARSET=UTF8 COLLATE utf8_general_ci&#8221;\/&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;\/modifySql&gt;<\/i><\/p>\n<p><i>&lt;\/changeSet&gt;<\/i><\/p>\n<p><i>&lt;changeSet author=&#8221;task&#8221; id=&#8221;1.0.0-2&#8243; dbms=&#8221;oracle,postgresql&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;createSequence sequenceName=&#8221;SEQ_TASK_PROJECTS_PROJECT_ID&#8221; startValue=&#8221;1&#8243;\/&gt;<\/i><\/p>\n<p><i>&lt;\/changeSet&gt;<\/i><\/p>\n<p><i>&#8230;<\/i><\/p>\n<p><i>&lt;changeSet author=&#8221;task&#8221; id=&#8221;1.0.0-23&#8243;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;createIndex indexName=&#8221;IDX_TASK_LABELS_01&#8243;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/i> <i>tableName=&#8221;TASK_LABELS&#8221;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;column name=&#8221;USERNAME&#8221; type=&#8221;NVARCHAR(50)&#8221;\/&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;\/createIndex&gt;<\/i><\/p>\n<p><i>&lt;\/changeSet&gt;<\/i><\/p>\n<p><i>&#8230;<\/i><\/p>\n<p><i>&lt;changeSet author=&#8221;task&#8221; id=&#8221;1.0.0-25&#8243;&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;addUniqueConstraint columnNames=&#8221;LABEL_ID, TASK_ID&#8221;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/i> <i>constraintName=&#8221;UQ_TASK_LABEL_TASK&#8221;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/i> <i>tableName=&#8221;TASK_LABEL_TASK&#8221;\/&gt;<\/i><\/p>\n<p><i>&lt;\/changeSet&gt;<\/i><\/p>\n<p>Le contenu complet du fichier de changelog de la version 1.0.0 de l\u2019application Task est disponible ici : <a href=\"https:\/\/raw.githubusercontent.com\/exoplatform\/task\/1.0.0\/services\/src\/main\/resources\/db\/changelog\/task.db.changelog-1.0.0.xml\" target=\"_blank\" rel=\"noopener\">https:\/\/raw.githubusercontent.com\/exoplatform\/task\/1.0.0\/services\/src\/main\/resources\/db\/changelog\/task.db.changelog-1.0.0.xml<\/a>.<\/p>\n<p>Une fois le change set appliqu\u00e9, Liquibase l\u2019enregistre afin de ne pas l\u2019appliquer de nouveau \u00e0 la prochaine mise \u00e0 jour.<\/p>\n<p>Il s\u2019appuie sur l\u2019ID de change set, il est donc tr\u00e8s important de ne pas modifier les ID une fois que les change sets correspondants ont \u00e9t\u00e9 appliqu\u00e9s, et de n\u2019avoir que des ID uniquement.<\/p>\n<p>eXo Platform ex\u00e9cute Liquibase \u00e0 chaque d\u00e9marrage. Pour l\u2019application Task par exemple, si ses donn\u00e9es n\u2019ont jamais \u00e9t\u00e9 initialis\u00e9es, tous les change sets de l\u2019application vont \u00eatre ex\u00e9cut\u00e9s au premier d\u00e9marrage.<\/p>\n<p>Ensuite, lors des d\u00e9marrages suivants, aucun changement ne sera appliqu\u00e9, jusqu\u2019\u00e0 ce que d\u2019autres change sets soient ajout\u00e9s.<\/p>\n<p>Un composant eXo Platform est disponible pour ajouter des nouveaux fichiers de changelog (pour les donn\u00e9es d\u2019applications m\u00e9tier par exemple). Il est utilisable dans une <a href=\"https:\/\/docs.exoplatform.org\/\" target=\"_blank\" rel=\"noopener\">extension<\/a>, comme n\u2019importe quel autre composant :<\/p>\n<p><i>&lt;external-component-plugins&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;target-component&gt;org.exoplatform.commons.api.persistence.DataInitializer&lt;\/target-component&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;component-plugin&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;name&gt;TaskManagementChangeLogsPlugin&lt;\/name&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;set-method&gt;addChangeLogsPlugin&lt;\/set-method&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;type&gt;org.exoplatform.commons.persistence.impl.ChangeLogsPlugin&lt;\/type&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;init-params&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;values-param&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;name&gt;changelogs&lt;\/name&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;description&gt;Change logs of task management&lt;\/description&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;value&gt;db\/changelog\/task.db.changelog-1.0.0.xml&lt;\/value&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;value&gt;db\/changelog\/task.db.changelog-1.1.0.xml&lt;\/value&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/values-param&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/init-params&gt;<\/i><\/p>\n<p><i> \u00a0\u00a0\u00a0&lt;\/component-plugin&gt;<\/i><\/p>\n<p><i>&lt;\/external-component-plugins&gt;<\/i><\/p>\n<p>Le param\u00e8tre <strong>changelogs<\/strong> du composant permet de d\u00e9finir une liste de chemins (dans le classpath) pour les fichiers de changelog. Dans l\u2019exemple pr\u00e9c\u00e9dent, les changelogs des versions 1.0.0 et 1.1.0 de l\u2019application Task sont d\u00e9clar\u00e9s. La convention utilis\u00e9e dans eXo Platform est d\u2019avoir un fichier de change log par version de l\u2019application, mais ce n\u2019est qu\u2019une convention, libre \u00e0 vous de les organiser comme bon vous semble.<\/p>\n<p>Une fois ces fichiers ajout\u00e9s dans votre extension, vous \u00eates pr\u00eat \u00e0 initialiser votre premier mod\u00e8le de donn\u00e9es avec liquibase dans eXo Platform !<\/p>\n<p>Pour avoir plus d\u2019informations sur Liquibase, n\u2019h\u00e9sitez pas \u00e0 parcourir <a href=\"http:\/\/www.liquibase.org\/documentation\/index.html\" target=\"_blank\" rel=\"noopener\">la documentation officielle<\/a>.<\/p>\n<h2>Conclusion<\/h2>\n<p>Maintenant que vous savez comment d\u00e9clarer des entit\u00e9s JPA, configurer la persistence unit, cr\u00e9er les classes DAO, g\u00e9rer les transactions et l\u2019initialisation et la mise \u00e0 jour du mod\u00e8le de donn\u00e9es, vous \u00eates pr\u00eat \u00e0 d\u00e9velopper vos propres applications avec JPA !<\/p>\n<p>eXo Platform s\u2019occupe de toute la plomberie afin que vous vous concentriez sur l\u2019essentiel.<\/p>\n<p>A vous de jouer ! \ud83d\ude09<\/p>\n<p><strong><a href=\"https:\/\/www.exoplatform.com\/fr\/\" target=\"_blank\" rel=\"noopener\">D\u00e9couvrez comment eXo Platform peut vous aider \u00e0 transformer votre entreprise!<\/a><\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"Depuis la version 4.3, eXo Platform fournit une int\u00e9gration native avec JPA (Java Persistence API). JPA est une sp\u00e9cification d\u2019API Java pour la gestion de donn\u00e9es relationnelles dans les applications Java. Cette API permet de lier une classe Java (appel\u00e9e Entit\u00e9) avec une table de base de donn\u00e9es relationnelles \u00e0 l\u2019aide d\u2019annotations Java ou de [&hellip;]","protected":false},"author":64,"featured_media":12882,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"image","meta":[],"categories":[411],"tags":[608,1126],"lang":"fr","translations":{"fr":37082},"pll_sync_post":[],"_links":{"self":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts\/37082"}],"collection":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/users\/64"}],"replies":[{"embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/comments?post=37082"}],"version-history":[{"count":0,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/posts\/37082\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/media\/12882"}],"wp:attachment":[{"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/media?parent=37082"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/categories?post=37082"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.exoplatform.com\/blog\/wp-json\/wp\/v2\/tags?post=37082"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}