Erhalten Sie die ID des beibehaltenen Kind-Objekt in einer Eins-zu-viele-Beziehung
-
27-09-2019 - |
Frage
Ich habe zwei Entitätsklassen A und B, die sieht wie folgt aus.
public class A{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "a", fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
private List<B> blist = new ArrayList<B>();
//Other class members;
}
Klasse B:
public class B{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
private A a;
//Other class members;
}
habe ich ein Verfahren, das ein B-Objekt zu einem A-Objekt hinzufügt. Ich möchte die ID des neu hinzugefügten B-Objekt zurückzugeben.
Beispiel:
public Long addBtoA(long aID){
EntityTransaction tx = myDAO.getEntityManagerTransaction();
tx.begin();
A aObject = myDAO.load(aID);
tx.commit();
B bObject = new B();
bObject.addB(bObject);
tx.begin();
myDAO.save(aObject);
tx.commit();
//Here I want to return the ID of the saved bObject.
// After saving aObject it's list of B objects has the newly added bObject with it's id.
// What is the best way to get its id?
}
Lösung
habe ich ein Verfahren, das ein B-Objekt zu einem A-Objekt hinzufügt. Ich möchte die ID des neu hinzugefügten B-Objekt zurückzugeben.
Dann tun Sie es einfach! Nachdem die neue B-Instanz (und die geänderten gespült in die Datenbank) beibehalten wurde, seine id
zugewiesen wurde, schicken Sie es einfach. Hier ist ein Testverfahren, das dieses Verhalten veranschaulicht:
@Test
public void test_Add_B_To_A() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MyPu");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
A a = em.find(A.class, 1L);
B b = new B();
A.addToBs(b); // convenient method that manages the bidirectional association
em.getTransaction().commit(); // pending changes are flushed
em.close();
emf.close();
assertNotNull(b.getId());
}
übrigens, Ihr Code ist ein bisschen chaotisch, Sie zu commit
nach jeder Interaktion mit der EM nicht benötigen.
Andere Tipps
Ich glaube nicht, die akzeptierte Antwort richtig ist. Siehe https://coderanch.com/t/628230/framework / Frühjahr-Data-obtain-id-added
TLDR;
Sie sollten nur ein Repository für das Kind B
erstellen, so dass Sie das Kind von seinen Eltern völlig unabhängig speichern. Sobald Sie das gespeicherte B entity
dann verbinden sie an ihre Mutter A
haben.
Hier ist ein Beispielcode mit Todo
wobei die Eltern und Comment
ist das Kind.
@Entity
public class Todo {
@OneToMany(mappedBy = "todo", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<Comment> comments = new HashSet<>();
// getters/setters omitted.
}
@Entity
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
@JoinColumn(name = "todo_id")
private Todo todo;
// getters/setters omitted.
}
Wenn diese im Frühjahr Daten modelliert wurden, erstellen Sie zwei Repositories. TodoRepository
und CommentRepository
welche Autowired
in.
ein Rest Endpunkt empfangen kann POST /api/todos/1/comments
Gegeben einen Kommentar mit einer gegebenen todo ID zugeordnet werden soll.
@PostMapping(value = "/api/todos/{todoId}/comments")
public ResponseEntity<Resource<Comment>> comments(@PathVariable("todoId") Long todoId,
@RequestBody Comment comment) {
Todo todo = todoRepository.findOne(todoId);
// SAVE the comment first so its filled with the id from the DB.
Comment savedComment = commentRepository.save(comment);
// Associate the saved comment to the parent Todo.
todo.addComment(savedComment);
// Will update the comment with todo id FK.
todoRepository.save(todo);
// return payload...
}
Wenn Sie stattdessen haben Sie die unten ein und rettete den mitgelieferten Parameter comment
. Der einzige Weg, um den neuen Kommentar zu erhalten ist, durchläuft todo.getComments()
und das mitgelieferte comment
finden, die imo lästig und unpraktisch ist, wenn die Sammlung ein Set
ist.
@PostMapping(value = "/api/todos/{todoId}/comments")
public ResponseEntity<Resource<Comment>> comments(@PathVariable("todoId") Long todoId,
@RequestBody Comment comment) {
Todo todo = todoRepository.findOne(todoId);
// Associate the supplied comment to the parent Todo.
todo.addComment(comment);
// Save the todo which will cascade the save into the child
// Comment table providing cascade on the parent is set
// to persist or all etc.
Todo savedTodo = todoRepository.save(todo);
// You cant do comment.getId
// Hibernate creates a copy of comment and persists it or something.
// The only way to get the new id is iterate through
// todo.getComments() and find the matching comment which is
// impractical especially if the collection is a set.
// return payload...
}
Sie sollten zunächst die neu erstellte Objekt bestehen bleiben, fügen Sie es dann in seinen Behälter. Additionaly, kehrt die Methode der save
org.hibernate.Session
den Identifikator eines neu anhielt Objekts. So dass Sie nur Ihren Code und / oder Ihre DAO aktualisieren müssen, so verhalten:
newObject.setContainer(container); // facultative (only if the underlying SGBD forbids null references to the container)
Long id = (Long) hibernateSession.save(newObject); // assuming your identifier is a Long
container.add(newObject);
// now, id contains the id of your new object
Wie auch immer, für alle Objekt mit generierten IDs, kann man immer etwas tun:
hibernateSession.persist(object); // persist returns void...
return object.getId(); // ... but you should have a getId method anyway
Falls jemand keine Lösung auf früheren Kommentare finden, eine weitere Option hinzuzufügen
@GeneratedValue(strategy = yourChosenStrategy)
über die ID der Entität, die Sie (oder über die seine Getter) sind persistierende. In diesem Fall, wenn persist aufgerufen wird, wird die ID automatisch in dem persistenten Objekt eingestellt werden.
Hope, es hilft!