2012-12-12 32 views
8

Tôi có 2 thực thể: AccountAccountRole.Có cách nào để vượt qua đối tượng tách ra để JPA tồn tại không? (thực thể tách rời được chuyển sang tồn tại)

public class Account { 
    private AccountRole accountRole; 

    @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER) 
    public AccountRole getAccountRole() { 
     return accountRole; 
    } 

.

public class AccountRole { 
    private Collection<Account> accounts = new ArrayList<Account>(); 

    @OneToMany(mappedBy = "accountRole", fetch = FetchType.EAGER) 
    public Collection<Account> getAccounts() { 
     return accounts; 
    } 

Sự cố xảy ra khi tôi lấy tài khoảnBỏ từ cơ sở dữ liệu và cố gắng giữ nguyên Account. Tại thời điểm này tôi vừa tạo tài khoản và vai trò của mình đã tồn tại trong db.

AccountRole role = accountService.getRoleFromDatabase(AccountRoles.ROLE_USER); 
account.setAccountRole(role); 

//setting both ways, as suggested 
public void setAccountRole(AccountRole accountRole) { 
    accountRole.addAccount(this); 
    this.accountRole = accountRole; 
} 

entityManager.persist(account); // finally in my DAO 

tôi đọc này: JPA/Hibernate: detached entity passed to persistVà những gì tôi hiểu, tôi phải thiết lập các giá trị thực thể từ cả hai hướng, do đó những gì tôi đang làm trong setter của tôi.

Vẫn gặp lỗi.

org.hibernate.PersistentObjectException: detached entity passed to persist: foo.bar.pojo.AccountRole 

Trả lời

16

Chỉ cần thay thế

entityManager.persist(account); 

với:

entityManager.merge(account); 

Và cho phép hợp nhất tầng:

@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.EAGER) 
public AccountRole getAccountRole() { 
    return accountRole; 
} 

Bởi vì hợp nhất thực hiện điều này:

Nếu thực thể của bạn là mới, nó giống như một persist(). Nhưng nếu thực thể của bạn đã tồn tại, nó sẽ cập nhật nó.

+0

Cũng lưu ý rằng 'persist()' sẽ tạo đối tượng mà bạn đã truyền một thực thể được quản lý, tuy nhiên, hợp nhất sẽ trả về một bản sao được quản lý của đối tượng bạn đã truyền. Vì vậy, nếu bạn cần một thực thể quản lý sau khi hợp nhất bạn nên làm 'account = entityManager.merge (tài khoản)' Ngoài ra hãy xem [ở đây] (http://stackoverflow.com/a/1070629/1260908) – rumman0786

3

Dường như bạn rời khỏi giao dịch trong khi xử lý, do đó, accountRole bị tách rời hoặc đã được tách ra vì các lý do khác.

Gọi điện đến entityManager.merge(accountRole) trước khi gọi entityManager.persist(account) nên khắc phục.

EDIT: Thật không may, nếu bạn không thể chắc chắn nếu accountRole đã tồn tại trong DB, bạn sẽ phải kiểm tra bằng cách truy vấn. Nếu nó tồn tại - hợp nhất, nếu không - vẫn tồn tại. Nó thực sự là một rắc rối, nhưng tôi chưa thấy một giải pháp tốt hơn.

EDIT2: Thực thể bạn vượt qua với phương pháp merge sẽ vẫn vô tư - đơn vị quản lý sẽ được trả lại bởi merge, vì vậy bạn sẽ cần phải hợp nhất đầu tiên, sau đó thiết lập các tài liệu tham khảo trên account với giá trị trở lại của merge .

+0

trong những trường hợp hiếm hoi 'AccountRole' không tồn tại trong cơ sở dữ liệu, vì vậy khi thực hiện 'em.persist', tài khoản và tài khoản vẫn tồn tại và mọi thứ hoạt động. bây giờ khi tôi tìm thấy chính mình trong trường hợp đó với mã của bạn, nó đang cố gắng thêm 'AccountRole' hai lần vào cơ sở dữ liệu, đầu tiên với hợp nhất, với thành công và sau đó vẫn tồn tại, do đó cho tôi' lỗi trùng lặp giá trị khóa trùng lặp', mọi đề xuất ? vấn đề là, đôi khi vai trò không tồn tại. – Jaanus

+0

một giải pháp có thể là, nếu 'Vai trò' không tồn tại,' vẫn tồn tại 'toàn bộ điều chết tiệt, nhưng nếu vai trò tồn tại,' hợp nhất' nó trước, nhưng dường như quá phức tạp, phải không? – Jaanus

+0

@ Jananus - than ôi, bạn đúng :) Tôi đã chỉnh sửa câu trả lời cho phù hợp. – kostja

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