web-dev-qa-db-fra.com

Enregistrer des objets enfants automatiquement à l'aide de JPA Hibernate

J'ai une relation un-à-plusieurs entre table parent et enfant. Dans l'objet parent, j'ai un

List<Child> setChildren(List<Child> childs)

J'ai aussi une clé étrangère à la table des enfants. Cette clé étrangère est un ID qui fait référence à une ligne parent dans la base de données. Donc, dans ma configuration de base de données, cette clé étrangère ne peut pas être NULL. Cette clé étrangère est également la clé primaire de la table parent.

Ma question est donc de savoir comment sauvegarder automatiquement les objets enfants en procédant comme suit:

session.save(parent);

J'ai essayé ce qui précède, mais je reçois une erreur de base de données en me plaignant que le champ de clé étrangère de la table Child ne peut pas être NULL. Existe-t-il un moyen d'indiquer à JPA de définir automatiquement cette clé étrangère dans l'objet Child afin de pouvoir enregistrer automatiquement les objets enfants?

Merci d'avance.

62
Marquinio

J'ai essayé ce qui précède, mais je reçois une erreur de base de données en me plaignant que le champ de clé étrangère de la table Child ne peut pas être NULL. Existe-t-il un moyen d'indiquer à JPA de définir automatiquement cette clé étrangère dans l'objet Child afin de pouvoir enregistrer automatiquement les objets enfants?

Eh bien, il y a deux choses ici.

Tout d’abord, vous devez mettre en cascade l’opération de sauvegarde (mais je crois comprendre que vous le faites sinon vous n’obtiendrez pas de violation de contrainte FK lors de l’insertion dans la table "enfant")

Deuxièmement, vous avez probablement une association bidirectionnelle et je pense que vous ne définissez pas "les deux côtés du lien" correctement. Vous êtes censé faire quelque chose comme ça:

Parent parent = new Parent();
...
Child c1 = new Child();
...
c1.setParent(parent);

List<Child> children = new ArrayList<Child>();
children.add(c1);
parent.setChildren(children);

session.save(parent);

Un modèle courant consiste à utiliser des méthodes de gestion de liens:

@Entity
public class Parent {
    @Id private Long id;

    @OneToMany(mappedBy="parent")
    private List<Child> children = new ArrayList<Child>();

    ...

    protected void setChildren(List<Child> children) {
        this.children = children;
    }

    public void addToChildren(Child child) {
        child.setParent(this);
        this.children.add(child);
    }
}

Et le code devient:

Parent parent = new Parent();
...
Child c1 = new Child();
...

parent.addToChild(c1);

session.save(parent);

Les références

64
Pascal Thivent

Je crois que vous devez définir l'option de cascade dans votre mapping via xml/annotation. Reportez-vous à exemple de référence Hibernate ici .

Si vous utilisez une annotation, vous devez faire quelque chose comme ceci,

@OneToMany(cascade = CascadeType.PERSIST) // Other options are CascadeType.ALL, CascadeType.UPDATE etc..
27
Adeel Ansari

Voici les manières d'assigner un objet parent à un objet enfant de relations bidirectionnelles?

Supposons que vous ayez une relation disons un-à-plusieurs, puis pour chaque objet parent, un ensemble d'objet enfant existe. Dans les relations bidirectionnelles, chaque objet enfant aura une référence à son parent.

eg : Each Department will have list of Employees and each Employee is part of some department.This is called Bi directional relations.

Pour ce faire, one way consiste à attribuer un parent à un objet enfant tout en conservant l'objet parent

Parent parent = new Parent();
...
Child c1 = new Child();
...
c1.setParent(parent);

List<Child> children = new ArrayList<Child>();
children.add(c1);
parent.setChilds(children);

session.save(parent);

Autre moyen c'est-à-dire que vous pouvez utiliser hibernate Intercepter, ce qui vous permet de ne pas écrire le code ci-dessus pour tous les modèles.

Hibernate interceptor fournit des apis pour effectuer votre propre travail avant d'effectuer toute opération de base de données. De même, onSave d'objet, nous pouvons affecter l'objet parent dans des objets enfants à l'aide de la réflexion.

public class CustomEntityInterceptor extends EmptyInterceptor {

    @Override
    public boolean onSave(
            final Object entity, final Serializable id, final Object[] state, final String[] propertyNames,
            final Type[] types) {
        if (types != null) {
            for (int i = 0; i < types.length; i++) {
                if (types[i].isCollectionType()) {
                    String propertyName = propertyNames[i];
                    propertyName = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
                    try {
                        Method method = entity.getClass().getMethod("get" + propertyName);
                        List<Object> objectList = (List<Object>) method.invoke(entity);

                        if (objectList != null) {
                            for (Object object : objectList) {
                                String entityName = entity.getClass().getSimpleName();
                                Method eachMethod = object.getClass().getMethod("set" + entityName, entity.getClass());
                                eachMethod.invoke(object, entity);
                            }
                        }

                    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return true;
    }

}

Et vous pouvez enregistrer Intercepter dans la configuration en tant que

new Configuration().setInterceptor( new CustomEntityInterceptor() );
2
Sunil Kumar

Utilisation org.hibernate.annotations pour Cascade, si hibernate et JPA sont utilisés ensemble, on se plaint en quelque sorte de la sauvegarde des objets enfants.

1
sandhya nayak

Le programme suivant décrit le fonctionnement des relations bidirectionnelles en veille prolongée. Lorsque le parent va enregistrer sa liste d'objet enfant sera automatiquement enregistré.

      @Entity
      @Table(name="clients")
     public class Clients implements Serializable  {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)     
     @OneToMany(mappedBy="clients", cascade=CascadeType.ALL)
      List<SmsNumbers> smsNumbers;

    on the parent side
     and put the following annotation on the child side




 @Entity
  @Table(name="smsnumbers")
 public class SmsNumbers implements Serializable {
   @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
   int id;
   String number;
   String status;
 Date reg_date;
 @ManyToOne
 @JoinColumn(name = "client_id")
 private Clients clients;
  and getter setter.





    public static void main(String arr[])
   {
       Session session = HibernateUtil.openSession();
     //getting transaction object from session object
       session.beginTransaction();

        Clients cl=new Clients("Murali", "1010101010");
          SmsNumbers sms1=new SmsNumbers("99999", "Active", cl);
          SmsNumbers sms2=new SmsNumbers("88888", "InActive", cl);
          SmsNumbers sms3=new SmsNumbers("77777", "Active", cl);
          List<SmsNumbers> lstSmsNumbers=new ArrayList<SmsNumbers>();
          lstSmsNumbers.add(sms1);
          lstSmsNumbers.add(sms2);
          lstSmsNumbers.add(sms3);
          cl.setSmsNumbers(lstSmsNumbers);
     session.saveOrUpdate(cl);
     session.getTransaction().commit(); 
    session.close();    
1
shriram

dans votre setChilds, vous pouvez essayer de passer en boucle dans la liste et de faire quelque chose comme

child.parent = this;

vous devez également configurer la cascade du parent sur les valeurs appropriées.

0
hvgotcodes

En bref, définissez le type de cascade pour tous, fera un travail; Pour un exemple dans votre modèle. Ajouter un code comme celui-ci. @OneToMany (mappedBy = "reçu", cascade = CascadeType.ALL) liste privée saleSet;

0
Dila Gurung