الحصول على معرف الكائن الطفل المستمر في علاقة واحدة
-
27-09-2019 - |
سؤال
لدي فئتان كيان A و B الذي يبدو على النحو التالي.
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;
}
الصف ب:
public class B{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne
private A a;
//Other class members;
}
لدي طريقة تضيف كائن B إلى كائن A. أريد إعادة معرف الكائن B المضافة حديثًا.
على سبيل المثال:
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?
}
المحلول
لدي طريقة تضيف كائن B إلى كائن A. أريد إعادة معرف الكائن B المضافة حديثًا.
ثم فقط افعل ذلك! بعد استمرار مثيل B الجديد (وتغيير تم مسحه إلى قاعدة البيانات) ، id
تم تعيينه ، فقط أعده. فيما يلي طريقة اختبار توضح هذا السلوك:
@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());
}
بالمناسبة ، رمزك فوضوي بعض الشيء ، لا تحتاج إلى ذلك commit
بعد كل تفاعل مع EM.
نصائح أخرى
لا أعتقد أن الإجابة المقبولة صحيحة. يرى https://coderanch.com/t/628230/framework/spring-data-Obaint-id-Added
TLDR ؛ يجب عليك فقط إنشاء مستودع للطفل B
حتى تتمكن من إنقاذ الطفل بشكل مستقل تمامًا عن والديه. بمجرد أن يتم حفظه B entity
ثم ربطها إلى والديها A
.
هنا بعض رمز العينة مع Todo
كونه الوالد و Comment
كونه الطفل.
@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.
}
إذا تم تصميم هذا في بيانات الربيع ، فأنت تقوم بإنشاء مستودعين. TodoRepository
و CommentRepository
و هو Autowired
في.
بالنظر إلى نقطة نهاية راحة قادرة على تلقي المنشور /api/todos/1/comments
لربط تعليق جديد مع معرف TODO المعطى.
@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...
}
إذا فعلت بدلاً من ذلك ، وحفظت المعلمة المقدمة comment
. الطريقة الوحيدة للحصول على التعليق الجديد هي التكرار من خلال todo.getComments()
وابحث عن توفيرها comment
وهو أمر مزعج وغير عملي إذا كانت المجموعة Set
.
@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...
}
يجب أن تستمر في كائنك الذي تم إنشاؤه حديثًا أولاً ، ثم إضافته إلى الحاوية الخاصة به. الإضافة ، و save
طريقة org.hibernate.Session
إرجاع معرف كائن مستمر حديثًا. لذلك عليك فقط تحديث الكود و/أو DAO الخاص بك للتصرف مثل هذا:
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
على أي حال ، لجميع الكائنات ذات المعرفات التي تم إنشاؤها ، يمكنك دائمًا القيام بشيء مثل هذا:
hibernateSession.persist(object); // persist returns void...
return object.getId(); // ... but you should have a getId method anyway
في حال لم يجد شخص ما حلًا بشأن التعليقات السابقة ، فإن هناك خيارًا آخر هو إضافة
@GeneratedValue(strategy = yourChosenStrategy)
على معرف الكيان الذي تستمر (أو على getter). في هذه الحالة ، عندما يتم استدعاء ، سيتم تعيين المعرف تلقائيًا في الكائن المستمر.
أتمنى أن يساعد!