2009-01-20 11 views
10

J'ai deux clases connexes annotées JPA. Alarme et statut. Une alarme peut avoir un statut.JPA ne génère pas de restrictions FK «sur suppression de l'ensemble»

Ce dont j'ai besoin, c'est de pouvoir supprimer un état et "propager" une valeur nulle aux alarmes qui sont dans cet état qui a été supprimé.

En d'autres termes, j'ai besoin que la clé étrangère soit définie comme "lors de la suppression de l'ensemble".

@Entity 
public class Alarm { 
    @Id 
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequence") 
    @SequenceGenerator(name="sequence", sequenceName="alarm_pk_seq") 
    private Integer id; 

    @OneToOne(cascade=CascadeType.ALL) 
    @JoinColumn(name="idStatus") 
    private Status status; 

    // get/set 
} 

@Entity 
public class Status { 
    @Id 
    @Column(name="idStatus") 
    private Integer id; 

    private String description; 

    // get/set 
} 

Exemple:

Avant:

STATUS 
id description 
1 new 
2 assigned 
3 closed 

ALARMS 
id status 
1 1 
2 2 
3 2 

Après (suppression de l'état avec id = 2)

STATUS 
id description 
1 new 
3 closed 

ALARMS 
id status 
1 1 
2 NULL 
3 NULL 

J'utilise Hibernate et PostgreSQL, la génération automatique de la base de données à partir du code source. J'ai essayé avec tous les CascadeType possibles sans succès.

Y a-t-il quelque chose qui ne va pas dans le code? Est-il possible de le faire avec JPA?

Répondre

0

Etes-vous sûr de votre @OneToOne? Il me semble que vous préférez utiliser @ManyToOne (comme un statut peut être affecté à plusieurs alarmes):

@Entity 
public class Alarm { 
    ... 

    @ManyToOne(cascade=CascadeType.ALL) 
    @JoinColumn(name="idStatus", nullable=true) 
    private Status status; 

    ... 
} 
+0

Merci. Vous avez raison, je l'ai juste changé en une relation ManyToOne, et j'ai ajouté le paramètre nullable = true, mais le résultat est toujours le même :( –

3

ajouter que en utilisant l'annotation Hibernate:

@OnDelete(action=OnDeleteAction.CASCADE) 

génère l'étranger clé comme: "SUR MISE À JOUR PAS D'ACTION SUR SUPPRIMER CASCADE;"

Mais il n'y a pas d'action = OnDeleteAction.SET_NULL

De plus, je n'aime pas lier mon code pour hibernate si possible (mais je peux vivre avec si cela fonctionne).

Cette thread l'explique. Je ne peux pas croire qu'il n'y a pas une méthode facile dans JPA (ou extensions Hibernate) pour générer la clé étrangère.

2

Dans votre cas, vous générez la base de données à partir des classes. Cela impliquerait que vous n'utiliserez pas la base de données à d'autres fins (car cela vous forcerait à avoir des scripts DDL). Cela signifie que cette règle implémentée dans la base de données ou dans le code java est sans importance. Nous savons aussi que Hibernate soulèverait une exception transitoire dans le cas où l'on supprimerait un ou plusieurs statuts et essayerait de le référencer lors d'une validation sans cascade.

De plus, la base de données sera générée à l'aide d'une contrainte de clé étrangère. Tout ce qui signifie que la contrainte DOIT être respectée pour que l'application fonctionne.

Si vos entités sont dans un pot à part, vous pouvez ajouter une méthode transitoire à l'alarme ou à l'interface d'état pour supprimer un statut tout en respectant la règle.

En outre, les programmeurs, lors de l'utilisation des entités seront forcés de respecter la règle sinon le code ne fonctionnera pas. Mais pour faciliter la tâche, vous pouvez rendre la relation bidirectionnelle afin que la tâche de repérer les alarmes à partir des statuts soit facilitée.

Si vous le pouvez, utilisez un intercepteur/écouteur ondelete pour définir la propriété alarm.status sur null.

-1

OpenJPA a

@ForeignKey(deleteAction=ForeignKeyAction.NULL) 

mais il n'y a pas de moyen JPA standard pour le faire (et apparemment c'est impossible avec Hibernate).

Ça me donne envie de retourner à JDO.