الحصول على معرف الكائن الطفل المستمر في علاقة واحدة

StackOverflow https://stackoverflow.com/questions/3439433

سؤال

لدي فئتان كيان 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). في هذه الحالة ، عندما يتم استدعاء ، سيتم تعيين المعرف تلقائيًا في الكائن المستمر.

أتمنى أن يساعد!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top