A comprehensive educational project demonstrating progressive JPA (Java Persistence API) concepts using Hibernate, designed for students learning database persistence in Java.
- Overview
- Features
- Project Structure
- Prerequisites
- Installation
- Configuration
- Usage
- Database Schema
- Learning Objectives
- Technologies Used
- Authors
This project uses a municipal governance domain model (Mayors, Communes, Departments) to demonstrate various JPA concepts across 6 progressive lessons. Each part focuses on specific JPA features, building upon previous knowledge to provide a comprehensive understanding of Java persistence.
Target Audience: Computer Science students learning enterprise Java development and ORM (Object-Relational Mapping) patterns.
- Create, Read, Update, Delete operations on entities
- One-to-One relationships (Maire � Commune)
- Many-to-One relationships (Commune � Departement)
- One-to-Many relationships (Departement � Communes)
- Composite primary keys with
@EmbeddedId - Entity lifecycle management
- Join table entities with composite keys
- Bidirectional many-to-many relationships
- Managing temporal data in relationships (date ranges)
@Embeddedobjects for value types@ElementCollectionfor basic type collections- Cascade operations with embedded objects
- Collection ordering with
@OrderBy
@MappedSuperclassinheritance pattern- Entity hierarchy and polymorphism
- Inherited field mapping
- Direct SQL execution via
createNativeQuery() - Aggregate functions (COUNT, SUM)
- Parameter binding in native queries
- Result set processing
- JPQL (Java Persistence Query Language) queries
@NamedQueryannotations- Type-safe queries with
TypedQuery - JOIN operations and aggregations
- Bulk operations (DELETE, UPDATE)
- Case-insensitive searching
Before running this project, ensure you have:
- Java Development Kit (JDK) 17 or higher
- Apache Maven 3.6+ for dependency management
- MySQL 8.0+ database server
- IDE (IntelliJ IDEA, Eclipse, or VS Code recommended)
git clone <repository-url>
cd Projet-JPACreate the required databases and user:
-- Create databases
CREATE DATABASE bd_glid_2025;
CREATE DATABASE bd_glid_2025_partie2;
CREATE DATABASE bd_glid_2025_partie3;
CREATE DATABASE bd_glid_2025_partie4;
CREATE DATABASE bd_glid_2025_partie6;
-- Create user and grant privileges
CREATE USER 'app_glid_2025'@'localhost' IDENTIFIED BY 'app_glid_2025';
GRANT ALL PRIVILEGES ON bd_glid_2025.* TO 'app_glid_2025'@'localhost';
GRANT ALL PRIVILEGES ON bd_glid_2025_partie2.* TO 'app_glid_2025'@'localhost';
GRANT ALL PRIVILEGES ON bd_glid_2025_partie3.* TO 'app_glid_2025'@'localhost';
GRANT ALL PRIVILEGES ON bd_glid_2025_partie4.* TO 'app_glid_2025'@'localhost';
GRANT ALL PRIVILEGES ON bd_glid_2025_partie6.* TO 'app_glid_2025'@'localhost';
FLUSH PRIVILEGES;mvn clean installThe project uses persistence.xml located at src/main/resources/META-INF/persistence.xml to configure 5 persistence units:
| Persistence Unit | Database | Schema Action |
|---|---|---|
exemple1 |
bd_glid_2025 |
update |
exemple2 |
bd_glid_2025_partie2 |
update |
exemple3 |
bd_glid_2025_partie3 |
update |
exemple4 |
bd_glid_2025_partie4 |
update |
exemple6 |
bd_glid_2025_partie6 |
create-drop |
Connection Settings:
- URL:
jdbc:mysql://localhost:3306/<database> - Driver:
com.mysql.cj.jdbc.Driver - Username:
app_glid_2025 - Password:
app_glid_2025
To modify database credentials, edit persistence.xml:
<property name="jakarta.persistence.jdbc.user" value="your_username"/>
<property name="jakarta.persistence.jdbc.password" value="your_password"/>Run the main application to explore basic CRUD operations:
mvn exec:java -Dexec.mainClass="tn.ensit.info3.glid.projet_jpa.App"Features demonstrated:
ecrire()- Create a new mayor with user inputchercher()- Find mayor by IDmodifier()- Update mayor informationsupprimer()- Delete mayor by IDcreerCommune()- Create commune with associated mayorchercherCommune()- Retrieve commune and its mayor
Entity Relationships:
Maire�Commune(One-to-One bidirectional)Commune�Departement(Many-to-One)Departement�Communes(One-to-Many)
Example Code:
// Create EntityManager
EntityManagerFactory emf = Persistence.createEntityManagerFactory("exemple1");
EntityManager em = emf.createEntityManager();
// Create a new mayor
em.getTransaction().begin();
Maire maire = new Maire("Dupont", "Jean", Civilite.M);
em.persist(maire);
em.getTransaction().commit();
// Find by ID
Maire found = em.find(Maire.class, 1L);
System.out.println(found.getNom());Demonstrates join table pattern with temporal data:
mvn exec:java -Dexec.mainClass="tn.ensit.info3.glid.projet_jpa.AppPartie2"Key Concepts:
CommuneMairejoin entity with composite key- Tracking start/end dates for relationships
- Bidirectional many-to-many associations
Run to see embedded objects and element collections:
mvn exec:java -Dexec.mainClass="tn.ensit.info3.glid.projet_jpa.AppPartie3"Features:
demoComposition()- Embedded address objects within mayorsdemoCollections()- Element collections for email addresses
Example:
// Create mayor with embedded address
Maire maire = new Maire("Martin", "Sophie", Civilite.Mme);
Adresse adresse = new Adresse("123 Rue de la Paix", commune);
maire.setAdresse(adresse);
// Add email collection
Set<String> emails = new HashSet<>();
emails.add("sophie.martin@mairie.fr");
maire.setEmails(emails);Demonstrates @MappedSuperclass inheritance:
mvn exec:java -Dexec.mainClass="tn.ensit.info3.glid.projet_jpa.AppPartie4"Inheritance Hierarchy:
Utilisateur (@MappedSuperclass)
� Employe (@Entity)
Example:
Employe employe = new Employe();
employe.setNom("Durand");
employe.setSalaire(35000.0);
em.persist(employe);Execute native SQL queries:
mvn exec:java -Dexec.mainClass="tn.ensit.info3.glid.projet_jpa.AppPartie5"Methods:
afficherNombreMaires()- Count total mayorsafficherNomsAdressesMaires()- List names and addressesafficherNomAdressMaire()- Find specific mayor
Example:
// Native SQL with parameter binding
String sql = "SELECT * FROM maire WHERE nom = :nom";
Query query = em.createNativeQuery(sql, Maire.class);
query.setParameter("nom", "Dupont");
List<Maire> results = query.getResultList();Advanced querying with JPQL:
mvn exec:java -Dexec.mainClass="tn.ensit.info3.glid.projet_jpa.AppPartie6"Features:
afficherMaires()- Retrieve all mayorsafficherDepartementPopulation()- Aggregate queries with JOINafficherStatistiquesCommunes()- Statistics with COUNT/SUMsupprimerMaires()- Bulk delete operations
Example JPQL:
// Type-safe JPQL query
TypedQuery<Maire> query = em.createQuery(
"SELECT m FROM Maire m WHERE LOWER(m.nom) LIKE :pattern",
Maire.class
);
query.setParameter("pattern", "%dupont%");
List<Maire> results = query.getResultList();
// Named query usage
TypedQuery<Commune> query = em.createNamedQuery("Commune.byName", Commune.class);
query.setParameter("nom", "Paris");
Commune commune = query.getSingleResult();Tables:
maire(id, nom, prenom, civilite, commune_id)commune(id, nom, departement_id)departement(id, nom)classe(niveau, annee, nombreEE) - Composite key
Constraints:
- UNIQUE(nom, prenom) on maire table
- Foreign keys with cascade options
Additional Fields:
maire.adresse_adresse- Embedded address stringmaire.adresse_commune_id- Embedded commune referencemaire_emails- Collection table for email addresses
| Annotation | Purpose | Example Entity |
|---|---|---|
@Entity |
Marks a class as a JPA entity | All model classes |
@Id |
Defines primary key | All entities |
@GeneratedValue |
Auto-generates ID values | Maire, Commune |
@OneToOne |
One-to-one relationship | Maire � Commune |
@ManyToOne |
Many-to-one relationship | Commune � Departement |
@OneToMany |
One-to-many relationship | Departement � Communes |
@Embedded |
Embeds value object | Maire.adresse |
@Embeddable |
Marks class as embeddable | Adresse |
@ElementCollection |
Collection of basic types | Maire.emails |
@EmbeddedId |
Composite primary key | Classe |
@MappedSuperclass |
Inheritance base class | Utilisateur |
@NamedQuery |
Pre-defined query | Commune.byName |
@Enumerated |
Maps enum to DB | Civilite |
By working through this project, you will learn:
-
JPA Fundamentals
- Entity lifecycle (transient, managed, detached, removed)
- Persistence context and EntityManager
- Transaction management
-
Relationship Mapping
- Unidirectional vs bidirectional relationships
- Cascade types (PERSIST, REMOVE, ALL)
- Fetch strategies (LAZY vs EAGER)
- Join strategies and foreign keys
-
Advanced Mapping
- Composite keys with
@EmbeddedId - Embedded objects with
@Embedded - Element collections
- Inheritance strategies
- Composite keys with
-
Querying
- JPQL (Java Persistence Query Language)
- Native SQL queries
- Named queries for reusability
- Aggregate functions and joins
- Bulk operations
-
Best Practices
- Entity design patterns
- Performance optimization
- Transaction boundaries
- Lazy loading pitfalls
| Technology | Version | Purpose |
|---|---|---|
| Java | 17 | Programming language |
| Maven | 3.x | Build automation and dependency management |
| JPA | 3.x | Java Persistence API specification |
| Hibernate | 7.1.10.Final | JPA provider and ORM framework |
| MySQL | 8.0+ | Relational database management system |
| MySQL Connector/J | 9.5.0 | JDBC driver for MySQL |
| JUnit Jupiter | 5.11.0 | Unit testing framework |
Institution: ENSIT (�cole Nationale Sup�rieure d'Informatique et des T�l�communications)
Program: Information Technology - Year 3
Course: Database Management and JPA
This project is for educational purposes only.
Happy Learning! If you encounter any issues, please review the configuration settings and ensure your MySQL database is properly set up.