package fr.openwide.core.test.cascade;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import fr.openwide.core.jpa.exception.SecurityServiceException;
import fr.openwide.core.jpa.exception.ServiceException;
import fr.openwide.core.test.AbstractJpaCoreTestCase;
import fr.openwide.core.test.business.company.model.Company;
import fr.openwide.core.test.business.person.model.Person;
public class TestCascades extends AbstractJpaCoreTestCase {
@Test
public void testCreate() throws ServiceException, SecurityServiceException {
Company company = new Company("Company Test Persist");
Company company1 = new Company("Company Test Persist 1");
Company company2 = new Company("Company Test Persist 2");
Company company3 = new Company("Company Test Persist 3");
Company company4 = new Company("Company Test Persist 4");
Company company5 = new Company("Company Test Persist 5");
Company company6 = new Company("Company Test Persist 6");
Person person = new Person("Persist", "Numéro");
Person person1 = new Person("Persist1", "Numéro1");
Person person2 = new Person("Persist2", "Numéro2");
Person person3 = new Person("Persist3", "Numéro3");
Person person4 = new Person("Persist4", "Numéro4");
Person person5 = new Person("Persist5", "Numéro5");
Person person6 = new Person("Persist6", "Numéro6");
/* Aucune Cascade (avec une table Join) :
*
* Lorsque l'on tente de créer la Company liée à une Person non persisté,
* on déclenche une exception. Il faut absolument que la Person existe dans
* la base pour remplir correctement la table Join de cette relation. Il faut
* donc créer la Person avant de créer la Company.
*/
company.addEmployee(person);
try {
companyService.create(company);
Assert.fail("La création d'une entité liée à un élément non persisté lève une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(companyService.list().contains(company));
Assert.assertFalse(personService.list().contains(person));
}
company = new Company("Company Test Persist");
person = new Person("Persist", "Numéro");
company.addEmployee(person);
personService.create(person);
companyService.create(company);
Assert.assertTrue(companyService.list().contains(company));
Assert.assertTrue(personService.list().contains(person));
/* Cascade SAVE_UPDATE :
*
* La méthode create() utilise la méthode save(). La cascade
* SAVE_UPDATE est donc activée lors de la création de la
* Company et la personne non persisté est crée. La table Join
* peut donc être remplie avec l'id de la Person persistée.
*/
company1.addEmployee1(person1);
companyService.create(company1);
Assert.assertTrue(companyService.list().contains(company1));
Assert.assertTrue(personService.list().contains(person1));
/* Cascade PERSIST :
*
* La méthode create() provoque un persist jpa ; on a donc cascade de la création de l'utilisateur
*/
company2.addEmployee2(person2);
companyService.create(company2);
Assert.assertTrue(companyService.list().contains(company2));
Assert.assertTrue(personService.list().contains(person2));
/* Cascade REMOVE :
*
* La méthode create() ne déclenchent pas la cascade
* REMOVE. Lorsque l'on tente de créer la Company liée à une
* Person non persisté, on déclenche une exception. Il faut absolument que
* la Person soit persistée dans la base pour remplir correctement la table
* Join de cette relation. Il faut créer la Person avant de créer la Company.
*/
company3.addEmployee3(person3);
try {
companyService.create(company3);
Assert.fail("La création d'une entité liée à un élément non persisté lève une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(companyService.list().contains(company3));
}
/* Cascade DELETE :
*
* La méthode create() ne déclenchent pas la cascade
* DELETE. Lorsque l'on tente de créer la Company liée à une
* Person non persisté, on déclenche une exception. Il faut absolument que
* la Person soit persistée dans la base pour remplir correctement la table
* Join de cette relation. Il faut créer la Person avant de créer la Company.
*/
company4.addEmployee4(person4);
try {
companyService.create(company4);
Assert.fail("La création d'une entité liée à un élément non persisté lève une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(companyService.list().contains(company4));
}
/* Cascade DELETE_ORPHAN :
*
* La méthode create() ne déclenchent pas la cascade
* DELETE_ORPHAN. Lorsque l'on tente de créer la Company liée à une
* Person non persisté, on déclenche une exception. Il faut absolument que
* la Person soit persistée dans la base pour remplir correctement la table
* Join de cette relation. Il faut créer la Person avant de créer la Company.
*/
company5.addEmployee5(person5);
try {
companyService.create(company5);
Assert.fail("La création d'une entité liée à un élément non persisté lève une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(companyService.list().contains(company5));
}
/* Cascade MERGE :
*
* La méthode create() ne déclenchent pas la cascade
* MERGE. Lorsque l'on tente de créer la Company liée à une
* Person non persisté, on déclenche une exception. Il faut absolument que
* la Person soit persistée dans la base pour remplir correctement la table
* Join de cette relation. Il faut créer la Person avant de créer la Company.
*/
company6.addEmployee6(person6);
try {
companyService.create(company6);
Assert.fail("La création d'une entité liée à un élément non persisté lève une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(companyService.list().contains(company6));
}
}
@Test
public void testUpdate() throws ServiceException, SecurityServiceException {
Company company = createCompany("Company Test Update");
Person person = new Person("Update", "Numéro");
Person person1 = new Person("Update1", "Numéro1");
Person person2 = new Person("Update2", "Numéro2");
Person person3 = new Person("Update3", "Numéro3");
Person person4 = new Person("Update4", "Numéro4");
Person person5 = new Person("Update5", "Numéro5");
Person person6 = new Person("Update6", "Numéro6");
/* Aucune Cascade (avec une table Join) :
*
* Lorsque l'on update la Company, la Person non persistée n'est pas crée
* puisqu'il n'y a aucune cascade sur la relation. On a une exception car
* on essaye d'ajouter une personne qui n'est pas persistée.
*/
company.addEmployee(person);
try {
companyService.update(company);
Assert.fail("Le fait d'updater et d'avoir un élément non persisté lié à l'entité doit provoquer une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(personService.list().contains(person));
}
company = companyService.getById(company.getId());
personService.create(person);
companyService.update(company);
Assert.assertTrue(personService.list().contains(person));
/* Cascade SAVE_UPDATE :
*
* Lorsque l'on update la Company, la cascade SAVE_UPDATE est déclanchée et la
* Person non persistée est crée dans la base.
*/
company.addEmployee1(person1);
companyService.update(company);
Assert.assertTrue(personService.list().contains(person1));
/* Cascade PERSIST :
*
* Lorsque l'on update, la cascade PERSIST est déclenchée à la sortie du scope transactionnel (proxy companyService.*)
*/
company.addEmployee2(person2);
companyService.update(company);
Assert.assertTrue(personService.list().contains(person2));
personService.create(person2);
companyService.update(company);
Assert.assertTrue(personService.list().contains(person2));
/* Cascade REMOVE :
*
* Lorsque l'on update, la cascade PERSIST n'est pas déclanchée. On a une exception
* puisque l'on esssaye d'ajouter à la Company une Person qui n'est pas persistée.
*/
company.addEmployee3(person3);
try {
companyService.update(company);
Assert.fail("Le fait d'updater et d'avoir une cascade REMOVE sur un élément non persisté doit provoquer une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(personService.list().contains(person3));
}
company = companyService.getById(company.getId());
personService.create(person3);
companyService.update(company);
Assert.assertTrue(personService.list().contains(person3));
/* Cascade DELETE :
*
* Lorsque l'on update, la cascade REMOVE n'est pas déclanchée. On a une exception
* puisque l'on esssaye d'ajouter à la Company une Person qui n'est pas persistée.
*/
company.addEmployee4(person4);
try {
companyService.update(company);
Assert.fail("Le fait d'updater et d'avoir une cascade DELETE sur un élément non persisté doit provoquer une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(personService.list().contains(person4));
}
company = companyService.getById(company.getId());
personService.create(person4);
companyService.update(company);
Assert.assertTrue(personService.list().contains(person4));
/* Cascade DELETE_ORPHAN :
*
* Lorsque l'on update, la cascade PERSIST n'est pas déclanchée. On a une exception
* puisque l'on esssaye d'ajouter à la Company une Person qui n'est pas persistée.
*/
company.addEmployee5(person5);
try {
companyService.update(company);
Assert.fail("Le fait d'updater et d'avoir une cascade DELETE_ORPHAN sur un élément non persisté doit provoquer une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(personService.list().contains(person5));
}
company = companyService.getById(company.getId());
personService.create(person5);
companyService.update(company);
Assert.assertTrue(personService.list().contains(person5));
/* Cascade MERGE :
*
* Lorsque l'on update, la cascade PERSIST n'est pas déclanchée. On a une exception
* puisque l'on esssaye d'ajouter à la Company une Person qui n'est pas persistée.
*/
company.addEmployee6(person6);
try {
companyService.update(company);
Assert.fail("Le fait d'updater et d'avoir une cascade MERGE sur un élément non persisté doit provoquer une exception");
} catch (InvalidDataAccessApiUsageException e) {
Assert.assertFalse(personService.list().contains(person6));
}
company = companyService.getById(company.getId());
personService.create(person6);
companyService.update(company);
Assert.assertTrue(personService.list().contains(person6));
}
@Test
public void testDelete() throws ServiceException, SecurityServiceException {
Company company = createCompany("Company Test Delete");
Company company1 = createCompany("Company Test Delete 1");
Company company2 = createCompany("Company Test Delete 2");
Company company3 = createCompany("Company Test Delete 3");
Company company4 = createCompany("Company Test Delete 4");
Company company5 = createCompany("Company Test Delete 5");
Company company6 = createCompany("Company Test Delete 6");
Person person = createPerson("Delete", "Numéro");
Person person1 = createPerson("Delete1", "Numéro1");
Person person2 = createPerson("Delete2", "Numéro2");
Person person3 = createPerson("Delete3", "Numéro3");
Person person4 = createPerson("Delete4", "Numéro4");
Person person5 = createPerson("Delete5", "Numéro5");
Person person6 = createPerson("Delete6", "Numéro6");
/* Aucune Cascade (avec table Join) :
*
* Lorsque l'on essaye de supprimer la Company qui est liée à la Person,
* la relation est supprimée mais l'objet Person est conservé.
*/
company.addEmployee(person);
companyService.update(company);
personService.update(person);
Assert.assertTrue(companyService.list().contains(company));
companyService.delete(company);
Assert.assertFalse(companyService.list().contains(company));
Assert.assertTrue(personService.list().contains(person));
/* Cascade SAVE_UPDATE :
*
* Comme attendu, lors de la suppression de la Company, la cascade
* SAVE_UPDATE n'est pas déclenchée et la Person liée n'est pas supprimée.
*/
//company1.addEmployee1(person1);
companyService.update(company1);
Assert.assertTrue(companyService.list().contains(company1));
companyService.delete(company1);
Assert.assertFalse(companyService.list().contains(company1));
Assert.assertTrue(personService.list().contains(person1));
/* Cascade PERSIST :
*
* Comme attendu, lors de la suppression de la Company, la cascade
* PERSIST n'est pas déclenchée et la Person liée n'est pas supprimée.
*/
company2.addEmployee2(person2);
companyService.update(company2);
Assert.assertTrue(companyService.list().contains(company2));
companyService.delete(company2);
Assert.assertFalse(companyService.list().contains(company2));
Assert.assertTrue(personService.list().contains(person2));
/* Cascade REMOVE :
*
* Même en utilisant delete(), la cascade REMOVE est activée
* et la Person liée à la Company est supprimée en cascade.
*/
company3.addEmployee3(person3);
companyService.update(company3);
Assert.assertTrue(companyService.list().contains(company3));
companyService.delete(company3);
Assert.assertFalse(companyService.list().contains(company3));
Assert.assertFalse(personService.list().contains(person3));
/* Cascade DELETE
*
* Dans cet exemple, on lie la Person à deux Company différentes,
* et on observe ce qui va se passer si on essaye de supprimer l'une
* des Company.
*/
company4.addEmployee4(person4);
companyService.update(company4);
company5.addEmployee1(person4);
companyService.update(company5);
/*
* Code qu'on avait avant : si jamais l'entité était encore attachée par ailleurs, la base renvoyait une exception
* et du coup, ça donnait une indication.
*
* Cependant, il semble que l'esprit de la norme JPA dit que si un objet à supprimer par cascade est attaché
* par ailleurs, la suppression doit être purement et simplement ignorée...
* Ca ne va pas nous aider à trouver les soucis mais, après discussion avec les gens d'Hibernate, ça restera comme cela...
*
try {
companyService.delete(company4);
Assert.fail("Supprimer en cascade une entité qui à encore des relations lève une exception");
} catch (JpaObjectRetrievalFailureException e) {
// La tentative de suppression de la personne viole une contrainte d'intégrité
// de la base de données. On ne peut pas supprimer en cascade une Person encore
// en relation avec d'autres Company. Pour parer à ce problème, pas de solution
// automatique, on doit délier l'entité pour pouvoir la supprimer en cascade.
company4 = companyService.getById(company4.getId());
company5 = companyService.getById(company5.getId());
Assert.assertTrue(companyService.list().contains(company4));
Assert.assertTrue(personService.list().contains(person4));
}*/
// on délie toute les relations et on doit donc pouvoir supprimer supprimer person4 par cascade sans souci
person4 = personService.getById(person4.getId());
company5.removeEmployee1(person4);
companyService.update(company5);
companyService.delete(company4);
Assert.assertNull(personService.getById(person4.getId()));
/* Une fois l'entité Person déliée de la seconde Company, elle est supprimée sans
* problèmes par la cascade.
*/
Assert.assertFalse(companyService.list().contains(company4));
Assert.assertFalse(personService.list().contains(person4));
/* Cascade DELETE_ORPHAN :
*
* La cascade DELETE_ORPHAN (ou orphanRemoval) va détruire, en plus des entités liées
* par la relation, les entités qui sont référencés comme anciennement liés. Pour mettre
* ce comportement en valeur, on lie une Person une Company puis on détruit le lien.
* Lorsque l'on supprime la Company, on constate que la Person est aussi détruite
*/
person5 = personService.getById(person5.getId());
company5.addEmployee5(person5);
companyService.update(company5);
Assert.assertTrue(companyService.list().contains(company5));
companyService.delete(company5);
Assert.assertFalse(companyService.list().contains(company5));
Assert.assertFalse(personService.list().contains(person5));
/* Cascade MERGE :
*
* Comme attendu, lors de la suppression de la Company, la cascade
* MERGE n'est pas déclenchée et la Person liée n'est pas supprimée.
*/
person6 = personService.getById(person6.getId());
company6 = companyService.getById(company6.getId());
company6.addEmployee6(person6);
companyService.update(company6);
Assert.assertTrue(companyService.list().contains(company6));
companyService.delete(company6);
Assert.assertFalse(companyService.list().contains(company6));
Assert.assertTrue(personService.list().contains(person6));
}
}