2013-07-23 35 views
6

Tôi có một thực thể mà trước đó đã được persited và có một mối quan hệ @OneToMany với một thực thể khác. Để thêm một thực thể mới, tôi chỉ cần thêm đối tượng mới vào đối tượng được quản lý và sử dụng cascadeType.ALL để tiếp tục thay đổi. Có cách nào mà tôi có thể nhận được id của các đối tượng mới được tạo ra hoặc nhận được đối tượng ban đầu (không được quản lý) mà tôi đã sử dụng với việc hợp nhất để cập nhật id của nó không?JPA Làm thế nào tôi có thể nhận được id/đối tượng được tạo khi sử dụng kết hợp từ cha mẹ nhưng con được tạo ra?

Trong pseudo-code Tôi mong chờ những điều sau đây xảy ra:

  1. bản mới sẽ được trả lại cho đơn vị sáp nhập
  2. Cũ bản sao sẽ được cập nhật cho các thực thể mới

Ví dụ: Cấp độ gốc A, id = 13 B đứa trẻ, id = 0

Thực chất, tôi muốn phát hành merge trên cha mẹ nhưng thác persist trên con (để phiên bản con ban đầu được cập nhật, không được sao chép).

Rõ ràng điều này không xảy ra. Tôi đang sử dụng chế độ ngủ đông làm nhà cung cấp.

+0

Bạn đang sử dụng cơ sở dữ liệu nào, nhà cung cấp JPA và chiến lược tạo id? Với Oracle 11g + Hibernate + '@ SequenceGenerator', các đối tượng ghép nối tốt và trả về với id được gán mới. –

+0

Tôi đang sử dụng MySql và '@ GeneratedValue'. Tôi không phải là một fan hâm mộ của id gộp lại mà tôi nghĩ là lý do tại sao nó hoạt động cho Oracle/'SequenceGenerator' –

+0

@johnd Tôi đã chỉnh sửa cho câu hỏi trong một nỗ lực để làm rõ; nếu tôi hiểu lầm, vui lòng quay lại những thay đổi của tôi. –

Trả lời

6

Stackoverflow postJPA documentation có câu trả lời với điều kiện là bạn làm nghiên cứu của bạn.

Cách để thực hiện những gì tôi muốn là sử dụng persist trên được quản lý cấp độ gốc. Điều này sẽ bỏ qua bất kỳ thay đổi nào đối với phụ huynh, nhưng sẽ xếp thứ tự persist (miễn là nó được thiết lập để xếp tầng). Đối tượng con sẽ có id chính xác sau đó.

.... 
JPAEntity newObject=new JPAEntity(); 
managedObject.addChild(newObject); 
em.persist(managedObject) 
newObject.getId() //work fine! 
1

Bạn sẽ có thể "nhìn thấy" một ID tạo ra cho một thực thể mới:

  • sau khi giao dịch cam kết, hoặc

  • sau một em.flush() (nơi em là bạn EntityManager) trong khi một giao dịch đang hoạt động.

Cũng lưu ý rằng tất cả mối quan hệ giữa các thực thể cần phải được giải quyết trong các cấu trúc dữ liệu Java kiên trì trước. Tài liệu tham khảo về trẻ em cho phụ huynh cần phải được "đặt" và ngược lại.

+0

Nếu tôi lặp qua thực thể được trả về (đã hợp nhất), tôi có thể thấy rằng id đã được đặt, không có vấn đề gì. Nhưng tôi không thể nhìn thấy một id trên bản gốc (con/không tồn tại đối tượng). –

+3

Thao tác hợp nhất tạo một bản sao * được quản lý mới * của đối tượng, trình quản lý đối tượng không theo dõi, thay đổi hoặc quản lý bản sao gốc không được quản lý ban đầu. Khi tôi hiểu câu hỏi của bạn, bạn sẽ không may mắn. –

0

Đảm bảo rằng bạn đang đặt cả hai trang web của mối quan hệ trước khi kiên trì các thay đổi.

child.setParent(parent); 
parent.getChildren().add(child); 
Parent parentWithId = em.merge(parent); 
em.flush(); // make sure that the persistence context and database are in sync 
parentWithId.getId(); // works 
parentWithId.getChildren().get(0).getId(); // should also work 
+0

Tôi đang thiết lập cả hai mặt của mối quan hệ và có, các tác phẩm trên. Nhưng tôi không muốn đi qua bộ sưu tập để tìm id mới (tôi là atm, nhưng tôi không thích nó). Có những cách giải quyết khác là tốt, nhưng tôi mong đợi một giải pháp trực tiếp hơn. –

+0

jonh, đây không phải là những gì bạn đã hỏi. Nếu bạn muốn làm việc với đối tượng gốc, sử dụng 'persist' trên parent, flush và refresh. http://stackoverflow.com/questions/4870863/why-jpa-persist-does-not-generated-auto-increment-primary-id –

1

Tôi gặp sự cố tương tự với eclipselink liên tục của nhà cung cấp. Tôi cần thêm các đơn đặt hàng mới từ cơ sở dữ liệu khách hàng với "orderID khách hàng" tạm thời cho một khách hàng hiện có trong cơ sở dữ liệu máy chủ. Bởi vì tôi cần "orderID máy chủ" để yêu cầu khách hàng hơn nữa, tôi muốn tạo bản đồ (clientID, serverID) và gửi lại cho khách hàng. Về cơ bản cách tiếp cận của tôi là để có được một tham chiếu đến bản sao của lệnh con mới được thêm vào. Nó sẽ luôn luôn được thêm vào cuối danh sách của tôi trong khách hàng lớp cha, thực tế đó được sử dụng để lấy nó.

Tôi sử dụng các lớp thực thể Khách hàng và Đơn đặt hàng, trong đó Khách hàng có danh sách các đơn đặt hàng (LinkedList).

Chánh lớp khách hàng: ...

@OneToMany(mappedBy = "customer", cascade=CascadeType.ALL, orphanRemoval = true) 
    private List<Order> orders = new LinkedList<Order>(); 

    public Order getLastOrder() { 
     return orders.get(orders.size()-1); 
    } 

tự Child lớp:

@ManyToOne(optional=false) 
    private Customer customer; 

Servlet:

Customer customer = customerService.findByID(customerID); //existing customer 
    Order order = new Order(); 
    //add attributes to new order 
    customer.addOrder(order); 
    customerService.update(customer); //generates keys for children 
    order = customer.getLastOrder(); 
    Long orderID = order.getID; //Nullpointer exception 

cập nhật hậu mãi khách hàng với EntityManager.merge nhưng tôi quên cập nhật tham chiếu trong servlet:

hậu mãi lớp:

public void update(Customer entity) { 
     entityManager.merge(entity); 
    } 

Tôi giải quyết nó theo cách này: lớp hậu mãi:

public Customer update(Customer entity) { 
     return entityManager.merge(entity); 
    } 

Servlet: ....

customer = customerService.update(customer); //generates keys for children 

Bây giờ tất cả mọi thứ hoạt động tốt.

Các vấn đề liên quan