Ich habe eine Eins-zu-Viele-Beziehung zwischen Eltern- und Kindertabelle. Im übergeordneten Objekt habe ich eine
List<Child> setChildren(List<Child> childs)
Ich habe auch einen Fremdschlüssel in der Child-Tabelle. Dieser Fremdschlüssel ist eine ID, die auf eine übergeordnete Zeile in der Datenbank verweist. In meiner Datenbankkonfiguration kann dieser Fremdschlüssel also nicht NULL sein. Auch dieser Fremdschlüssel ist der Primärschlüssel in der übergeordneten Tabelle.
Meine Frage ist also, wie ich die untergeordneten Objekte automatisch speichern kann, indem ich so etwas mache:
session.save(parent);
Ich habe das oben Genannte versucht, erhalte jedoch einen Datenbankfehler, der sich darüber beschwert, dass das Fremdschlüsselfeld in der untergeordneten Tabelle nicht NULL sein kann. Gibt es eine Möglichkeit, JPA anzuweisen, diesen Fremdschlüssel automatisch in das untergeordnete Objekt zu setzen, damit untergeordnete Objekte automatisch gespeichert werden können?
Danke im Voraus.
Antworten:
Hier gibt es zwei Dinge.
Zuerst müssen Sie den Speichervorgang kaskadieren (aber ich verstehe, dass Sie dies tun oder dass Sie beim Einfügen in die "untergeordnete" Tabelle keine Verletzung der FK-Einschränkung erhalten würden).
Zweitens haben Sie wahrscheinlich eine bidirektionale Zuordnung und ich denke, dass Sie "beide Seiten des Links" nicht richtig einstellen. Sie sollen so etwas tun:
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);
Ein gängiges Muster ist die Verwendung von Link-Management-Methoden:
@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); } }
Und der Code wird:
VerweiseParent parent = new Parent(); ... Child c1 = new Child(); ... parent.addToChildren(c1); session.save(parent);
quelle
Ich glaube, Sie müssen die Kaskadenoption in Ihrem Mapping über XML / Annotation festlegen. Siehe Referenzbeispiel für den Ruhezustand hier .
Wenn Sie Anmerkungen verwenden, müssen Sie Folgendes tun:
@OneToMany(cascade = CascadeType.PERSIST) // Other options are CascadeType.ALL, CascadeType.UPDATE etc..
quelle
@OneToMany(cascade = CascadeType.ALL)
, Insert existiert nicht!CascadeType.INSERT
wird ersetzt durchCascadeType.PERSIST
.CascadeType.PERSIST
. Es hat nicht funktioniert. Das Ersetzen durch hatCascadeType.ALL
das Problem behoben.Das folgende Programm beschreibt, wie bidirektionale Beziehungen im Ruhezustand funktionieren.
Wenn Eltern ihre Liste der untergeordneten Objekte speichern, wird diese automatisch gespeichert.
Auf der Elternseite:
@Entity @Table(name="clients") public class Clients implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @OneToMany(mappedBy="clients", cascade=CascadeType.ALL) List<SmsNumbers> smsNumbers; }
Und setzen Sie die folgende Anmerkung auf die untergeordnete Seite:
@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. }
Hauptklasse:
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(); }
quelle
In Ihren setChilds möchten Sie vielleicht versuchen, die Liste zu durchlaufen und so etwas zu tun
child.parent = this;
Sie sollten auch die Kaskade auf dem übergeordneten Element auf die entsprechenden Werte einstellen.
quelle
Hier sind die Möglichkeiten, ein übergeordnetes Objekt in einem untergeordneten Objekt mit bidirektionalen Beziehungen zuzuweisen.
Angenommen, Sie haben eine Beziehung, die Eins-zu-Viele sagt, dann existiert für jedes übergeordnete Objekt eine Reihe von untergeordneten Objekten. In bidirektionalen Beziehungen verweist jedes untergeordnete Objekt auf sein übergeordnetes Objekt.
Um dies zu erreichen, besteht eine Möglichkeit darin, Eltern im untergeordneten Objekt zuzuweisen, während das übergeordnete Objekt beibehalten wird
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);
Eine andere Möglichkeit ist, Intercepter im Ruhezustand zu verwenden. Auf diese Weise können Sie nicht für alle Modelle den obigen Code schreiben.
Hibernate Interceptor bietet APIs, mit denen Sie Ihre eigene Arbeit erledigen können, bevor Sie eine DB-Operation ausführen. Ebenso können wir unter Speichern von Objekten übergeordnete Objekte in untergeordneten Objekten mithilfe von Reflektion zuweisen.
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; } }
Und Sie können Intercepter für die Konfiguration als registrieren
new Configuration().setInterceptor( new CustomEntityInterceptor() );
quelle
Verwenden Sie
org.hibernate.annotations
dazuCascade
, wenn dashibernate
undJPA
zusammen verwendet wird, es sich irgendwie über das Speichern der untergeordneten Objekte beschwert.quelle
Kurz gesagt, Kaskadentyp für alle, wird einen Job machen; Ein Beispiel in Ihrem Modell. Fügen Sie Code wie folgt hinzu. @OneToMany (mappedBy = "Quittung", cascade = CascadeType.ALL) private List saleSet;
quelle