[Hibernate 3.4] Relation père-fils : Effacement d'un des fils
Bonjour à tous,
je désire gérer une relation Père-Fils, en enlevant un des fils.
Quelque chose comme ça :
monPere.getFils(); // 2 fils :
// hypothese : monFils1 est evidemment un des 2 fils de monPere
monPere.getFils().remove(monFils1);
monPereDAO.save(monPere);
// ici, en base, il n'y a plus que le Pere et un seul de ces fils
Voici ce que j'ai base :
T_PERE
ID : INTEGER /**cle primaire, non null*/
NAME : VARCHAR
T_FILS
ID : INTEGER /**cle primaire, non null*/
PERE_ID : INTEGER /**Cle etrangere vers T_PERE, non null */
NAME : VARCHAR
et en code Java :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| @Entity
@Table(name = "T_PERE")
public class Pere implements Serializable {
private static final long serialVersionUID = 1L;
/** The id. */
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pere_seq")
@SequenceGenerator(name = "pere_seq", allocationSize = 10, sequenceName = "SEQ_PERE_ID")
private Long id;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "PERE_ID")
private Set<Fils> fils = new HashSet<Fils>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setFils(Set<Fils> fils) {
this.fils = fils;
for (Fils aFils : this.filss) {
aFils .setPere(this);
}
}
public Set<Fils> getFils() {
return fils;
}
// ---------------------------------------------------------
public void addFils(Fils aFils) {
if (fils == null) {
fils = new HashSet<Fils>();
}
fils.add(aFils);
aFils.setPere(this);
}
public boolean remove(Fils aFils) {
// aFils.setPere(null);
return fils.remove(aFils);
}
}
@Entity
@Table(name = "T_FILS")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Fils implements Serializable {
private static final long serialVersionUID = 1L;
/** The id. */
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "fils_seq")
@SequenceGenerator(name = "fils_seq", allocationSize = 10, sequenceName = "SEQ_FILS_ID")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PERE_ID", nullable = false)
private Pere pere;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Pere getPere() {
if (pere instanceof HibernateProxy) {
Object r = ((HibernateProxy) pere).getHibernateLazyInitializer().getImplementation();
return (Pere) r;
} else {
return pere;
}
}
public void setPere(Pere pere) {
this.pere = pere;
}
// -----------------------------------------------------------
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Fils other = (Fils) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id)) {
return false;
}
return true;
}
} |
Le code "DAO" est du type suivant :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| @Repository
public class PereDAO {
public static Logger LOGGER = Logger.getLogger(PereDAO.class);
@PersistenceContext
protected EntityManager em;
/**
* Private constructor used to prevent from instantiation.
*
* Use DAOFactory.
*/
private PereDAO() {
super();
}
public Class<Pere> getModelClass() {
return Pere.class;
}
public Pere getById(Long id) throws DAOException {
try {
return em.find(getModelClass(), id);
} catch (Exception e) {
logger.error("Error while getting by id: " + id + " on " + getModelClass(), e);
throw new DAOException(e);
}
}
@SuppressWarnings("unchecked")
public List<Pere> findAll() throws DAOException {
try {
String q = "SELECT e FROM " + getModelClass().getSimpleName() + " e";
Query query = em.createQuery(q);
return (List<Pere>) query.getResultList();
} catch (Exception e) {
logger.error("Error while fetching all on " + getModelClass(), e);
throw new DAOException(e);
}
}
public void save(Pere object) throws DAOException {
try {
if (em.contains(object)) {
em.merge(object);
} else {
em.persist(object);
}
em.flush();
} catch (Exception e) {
logger.error("Error while saving: " + object + " on " + getModelClass(), e);
throw new DAOException(e);
}
}
public void merge(Pere object) throws DAOException {
try {
em.merge(object);
} catch (Exception e) {
logger.error("Error while saving: " + object + " on " + getModelClass(), e);
throw new DAOException(e);
}
}
public void flush() throws DAOException {
try {
em.flush();
} catch (Exception e) {
logger.error("Error while flushing on: " + getModelClass(), e);
throw new DAOException(e);
}
}
public void delete(E object) throws DAOException {
try {
object = em.merge(object);
em.remove(object);
} catch (Exception e) {
logger.error("Error while deleting: " + object + " on " + getModelClass(), e);
throw new DAOException(e);
}
}
} |
Dans ma classe de test, j'essaye de recupérer le père, puis d'enlever ses 2 fils, puis d'effacer le pere :
Code:
1 2 3 4 5 6 7 8
| Assert.assertEquals(2, monPere.getFils().size()); // ça passe
Set<Fils> allFils = new HashSet<Fils>(
monPere.getFils());
for (Fils monFils : allFils) {
monPere.remove(monFils);
// filsDAO.delete(monFils);
}
pereDao.delete(pere); |
Toutefois, à l'exécution, j'ai quand même l'erreur suivante :
Code:
1 2 3
| org.hibernate.exception.GenericJDBCException: Could not execute JDBC batch update
// ...
Caused by: java.sql.BatchUpdateException: ORA-01407: impossible de mettre à jour ("BASE_OWNER"."T_FILS"."PERE_ID") avec NULL |
J'ai la même erreur, y compris quand j'essaye d'effacer le fils directement avant d'effacer le père (cf code de test, en dé-commentant le code "filsDAO.delete(monFils)".
Question : Que faut il modifier pour que je puisse effacer un ou tous les fils d'un père ? Idem si je veux effacer directement toute l'arborescence (pere + fils) ?
Merci d'avance pour vos éclaircissements et vos idées de débugage.
Cordialement,