2013-03-15 27 views
8

Tôi đang xử lý biểu đồ đối tượng khá phức tạp trong cơ sở dữ liệu của mình. Tôi đang sử dụng XStream để serialize và deserialize đồ thị đối tượng này hoạt động tốt. Khi tôi nhập một biểu đồ đối tượng của một đối tượng tồn tại trong cơ sở dữ liệu, nó ban đầu thoáng qua, vì không có ID và hibernate không biết gì về nó. Sau đó tôi có logic nghiệp vụ đặt ID trên các phần của đồ thị đối tượng của tôi bằng cách tìm ra các đối tượng nào trong bản đồ đối tượng được chuyển đổi mới nhất sang các đối tượng liên tục hiện có. Sau đó tôi sử dụng hợp nhất Hibernate() và saveOrUpdate().Sử dụng thực thể thoáng qua trong Hibernate để cập nhật/Hợp nhất đối tượng liên tục hiện có

Một số giả để cung cấp cho bạn một ý tưởng tốt hơn về những gì tôi đang làm:

ComplexObject transObj = xstream.import("object.xml"); 
ComplexObject persistObj = someService.getObjByName(transObj.getName()); 
for (OtherObject o : c.getObjects()) { 
    if (persistObj.getObjects().contains(o.getName())) { 
     o.setId(persistObj.getObjectByName(o.getName()).getId()) 
    } 
    ... set a bunch of other IDs deeper in the object graph ... 
} 

transObj = session.merge(transObj); 
session.saveOrUpdate(transObj); 

Bây giờ điều này không làm việc khi tôi nhận được lỗi như:

org.springframework.dao.InvalidDataAccessApiUsageException: deleted object would be re-saved by cascade (remove deleted object from associations): [com.......SomeObject#353296]; nested exception is org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [com.......SomeObject#353296] 

và nó có vẻ như hợp nhất hibernate không có nghĩa là kết hợp các đối tượng tạm thời với các đối tượng liên tục.

Có cách nào để đạt được những gì tôi muốn làm mà không cần phải nhận đối tượng liên tục trong phiên và sửa đổi, thay vì sửa đổi tạm thời và cố gắng lưu và ghi đè liên tục hiện tại?

+1

Đó là cách tôi sẽ giải quyết nó: http://stackoverflow.com/questions/4779239/update-persistent-object-with-transient-object-using-hibernate - vì lý do hiệu suất mà bạn nên một trong hai bộ nhớ cache dữ liệu phản ánh/introspection hoặc tạo một trình tạo lớp từ các thực thể của bạn. – user1050755

+0

Có một setId luôn luôn là một ý tưởng tồi ...? – Rob

+0

user1050755, điều duy nhất về giải pháp đó là nó dường như không thể xử lý các thác phức tạp, một-nhiều, vv Tôi tưởng tượng điều này sẽ chỉ làm việc cho một cấu trúc kiểu không đồ thị, nhưng sửa tôi nếu tôi 'tôi sai. – eipark

Trả lời

8

nó có vẻ như ngủ đông hợp nhất không có nghĩa là cho kết thoáng đối tượng dai dẳng

Merge là tiêu chuẩn JPA - sáp nhập "mới & trường hợp tách đơn vị" đến "(kiên trì context-) quản lý các thể hiện thực thể ". Sẽ xếp hàng qua các mối quan hệ FK được đánh dấu là Cascade.MERGE hoặc Cascade.ALL.

Từ góc nhìn JPA - không, hợp nhất không có nghĩa là kết hợp các đối tượng tạm thời được truyền trực tuyến Xstream của bạn để liên tục. JPA dự định hợp nhất để làm việc với vòng đời JPA bình thường - tạo ra các đối tượng mới, liên tục, tìm/tìm chúng, tách chúng, sửa đổi chúng (bao gồm thêm đối tượng mới), hợp nhất chúng, tùy ý sửa đổi chúng một số, sau đó lưu giữ/lưu chúng . Đây là thiết kế có chủ ý, do đó JPA được xếp hàng theo dòng & performant - mỗi đối tượng riêng lẻ vẫn tồn tại trong cơ sở dữ liệu không cần phải đi trước trạng thái đối tượng để xác định xem có nên chèn/cập nhật hay không. Trạng thái đối tượng ngữ cảnh kiên trì JPA đã chứa đủ chi tiết để xác định điều này.

Vấn đề của bạn là bạn phải trường hợp pháp nhân mới mà bạn muốn hành động như thể họ đã được tách ra - và đó không phải là cách JPA.

SaveOrUpdate là một hoạt động độc quyền ngủ đông - nếu một thực thể có một danh tính được cập nhật, nhưng nếu nó không có thực thể thì nó sẽ được chèn vào.

Từ một ngủ đông quan điểm - có, hợp nhất tiếp theo saveOrUpdate về mặt lý thuyết có thể làm việc cho liên kết (XStream xem trực tiếp) đối tượng thoáng qua để dai dẳng, nhưng nó có thể có những hạn chế khi sử dụng trong conjuction với hoạt động JPA. saveOrUpdate DOES đứng trước mỗi đối tượng vẫn tồn tại trong cơ sở dữ liệu với một truy xuất để xác định xem/chèn/cập nhật gì - nó thông minh, nhưng nó không phải là JPA và nó không phải là trình diễn xuất sắc nhất. tức là bạn có thể làm điều này để làm việc với một số dịch vụ chăm sóc và cấu hình đúng - và sử dụng các hoạt động ngủ đông hơn là các hoạt động JPA khi xảy ra xung đột.

tôi nhận được lỗi như:

org.hibernate.ObjectDeletedException: xóa đối tượng sẽ được lưu lại bởi cascade (loại bỏ đối tượng đã bị xóa từ các hiệp hội): [com .... ... SomeObject # 353.296]

tôi tin rằng điều này có thể được gây ra bởi hai yếu tố:

  • nơi nào đó trong (XStream tạo) đồ thị đối tượng của bạn, một trường hợp đơn vị con là mất tích đó sẽ có mặt nếu bạn đã làm một (cascaded) lấy sử dụng JPA: điều này mang lại một xóa đối tượng
  • ở một nơi khác trong bạn (XStream -Đồ thị đối tượng), đối tượng con tương tự này có mặt: điều này cho phép đối tượng được lưu lại

    Cách gỡ lỗi này: (a) tạo biểu đồ đối tượng từ Xstream và in ra ĐẦY ĐỦ - mọi thực thể, mọi cánh đồng; (b) tải cùng một đồ thị đối tượng thông qua JPA, xếp tầng truy xuất từ ​​thực thể trên cùng & in nó ra ĐẦY ĐỦ - mọi thực thể, mọi trường (c) so sánh hai - là một cái gì đó thiếu từ (a) hiện diện trong (b) ??

Có cách nào để đạt được những gì tôi muốn làm mà không cần phải có được đối tượng liên tục trong phiên, và sửa đổi đó, thay vì sửa đổi một thoáng qua, và cố gắng để tiết kiệm đó và ghi đè lên hiện có liên tục?

Thông qua gỡ lỗi/sửa chữa vừa được đề xuất - hy vọng.

HOẶC gợi ý brute-force của tôi (dumbly) bên bước này lỗi (chậm hiệu suất một chút, mặc dù): sau khi bạn cư trú ID trong đồ thị đối tượng, gọi EntityManager.clear(), THEN tiến hành hợp nhất() và saveOrUpdate(). Nhưng UNIT KIỂM TRA kết quả DB - để đảm bảo bạn đã không bỏ qua điều gì đó quan trọng trong việc điền vào biểu đồ Xstream của bạn. Để thử nghiệm/như một phương sách cuối cùng, hãy thử saveOrUpdate() mà không cần hợp nhất(), nhưng sau đó bạn có thể bị buộc phải xóa() trình quản lý Thực thể để tránh ngoại lệ Hibernate, chẳng hạn như NonUniqueObjectException.

Hãy cho tôi biết nếu bạn tìm hiểu thêm/có nhiều thông tin B ^)

+0

Tôi đã cố gắng làm rõ ràng() và saveOrUpdate() mà không cần hợp nhất. Chúng tạo ra các lỗi ngủ đông khác ... Tôi nghĩ rằng như bản sao thực thể đã tồn tại và instantiation đối tượng instantiation. Tôi sẽ cung cấp cho các đề xuất khác của bạn một thử. Cảm ơn bạn đã trả lời kỹ lưỡng. – eipark

+0

Làm thế nào bạn sẽ "in" toàn bộ đối tượng? Đó chính là vấn đề ban đầu mà tôi đang làm, đó là nơi XStream bước vào. – eipark

1
Hibernate merge was not meant for associating transient objects 
to persistent ones. 

Các merge() lý tưởng nên làm việc cho bạn vì bạn đang thực sự đối phó với đối tượng tách ra. Vì bạn đang thiết lập id trong 'transObj' trước khi gọi hợp nhất, hibernate sẽ coi chúng là tách rời (không thoáng qua).

Tôi nghĩ rằng vấn đề với mã của bạn là nó đang vấp ngã ngủ đông.

Trong mã của bạn, bạn đang tải 'persistObj' từ cơ sở dữ liệu. Bây giờ, hibernate giữ 'persistObj' này trong phiên làm việc. Sau đó, bạn sẽ thiết lập một số id từ 'persistObj' trong 'transObj' và sau đó gọi hợp nhất. Một số đối tượng con trong 'persistObj' và 'transObj' có cùng id, hibernate bị lẫn lộn.

ComplexObject transObj = xstream.import("object.xml"); 
ComplexObject persistObj = someService.getObjByName(transObj.getName()); 
for (OtherObject o : c.getObjects()) { 
    if (persistObj.getObjects().contains(o.getName())) { 
     o.setId(persistObj.getObjectByName(o.getName()).getId()) 
    } 
    ... set a bunch of other IDs deeper in the object graph ... 
} 
transObj = session.merge(transObj); 
session.saveOrUpdate(transObj); 

Hãy thử gọi session.clear() sau khi tải 'persistObj', để hibernate loại bỏ persistBb và chỉ xem xét đối tượng tách rời của bạn.

ComplexObject transObj = xstream.import("object.xml"); 
ComplexObject persistObj = someService.getObjByName(transObj.getName()); 
// Clear the session, so that hibernate removes 'persistObj' from it's cache 
session.clear(); 
for (OtherObject o : c.getObjects()) { 
    if (persistObj.getObjects().contains(o.getName())) { 
     o.setId(persistObj.getObjectByName(o.getName()).getId()) 
    } 
    ... set a bunch of other IDs deeper in the object graph ... 
} 
transObj = session.merge(transObj); 
session.saveOrUpdate(transObj); 
+0

Nếu bạn kiểm tra nhận xét tôi đưa ra câu trả lời của Glen, tôi đã thử sử dụng rõ ràng trước khi merge() và saveOrUpdate() nhưng nó có xu hướng các vấn đề khác. Tôi sẽ thử lại một lần nữa và đưa ra một phản ứng rõ ràng hơn về lý do tại sao nó không hoạt động hoặc ít nhất một số thông báo lỗi. Cảm ơn. – eipark

+1

Xin lỗi, không thấy bình luận khác. Có, xin vui lòng gửi các lỗi bạn thấy với rõ ràng(). Tôi chắc chắn sẽ không có 'persistObt' và 'tranObj' được đính kèm vào cùng một phiên vì bạn đang cố gắng đại diện cho cùng một hàng cơ sở dữ liệu bằng cách sử dụng hai trường hợp khác nhau của đối tượng. Hibernate thường không cho phép điều này. – Sashi

+0

Tôi vừa thử lại lần nữa. Tôi chạy clearSession(), merge(), sau đó saveOrUpdate(). Giống như trong câu hỏi ban đầu của tôi, tôi nhận được đối tượng đã xóa sẽ bị lỗi được lưu lại. – eipark

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