2010-06-27 200 views
1

我在更新相關實體時遇到問題。JAVA JPA更新相關實體

讓我從一個簡單的例子開始。 假設我有一個用戶1:1配置文件關係。

如何更新(替換)屬於用戶的配置文件實體?

我曾嘗試沒有成功如下(均爲OneToOne關係具有的CascadeType = ALL屬性)

em.getTransaction().begin(); 

1.User.setProfile(Profile) 
.... 
2.User.setProfile(Profile) 
Profile.setUser(User) 
..... 
3.em.remove(User.getProfile()) 
User.setProfile(Profile) 
Profile.setUser(User) 

em.getTransaction().commit(); 

我和JPA完全糊塗了,也有一些有用的例子,但他們不是更新的實體(只是更新單個值,提高薪水等......)

我希望建議的方式也適用於1:N關係的情況。

+0

我不知道你是否可以這樣做。找到Profile obj併爲其分配一個新對象。 profile = new Profile(...) – 2015-08-12 00:14:56

回答

0

我在更新實體後總是做em.merge(user);。如果您有適當的級聯選項,那麼也會更新所有相關實體。

現在,我知道(聽說)實體應該在事務結束時更新數據庫本身,但我更喜歡直接調用。坦率地說,我發現整個「自動更新實體」模式比實際開發中的優勢更成爲一個問題。

+0

除非你有分離的實體,否則你不應該使用'em.merge()'。當實體管理器被刷新時,持久化上下文中的所有實體都會自動更新,一些(IMO不靈活的)框架在每次事務結束時強制執行。 – 2010-06-27 18:52:48

+0

@Joshua我不應該,但這種方式,它的工作:) – 2010-06-27 18:58:14

+0

你是不是這個意思? Profile.setUser(User); User.setProfile(Profile); em.merge(User); 或 User.setProfile(Profile); em.merge(User); 他們不工作......新的配置文件被保存,但它不能取代舊配置文件。 我錯了什麼? – cscsaba 2010-06-27 19:09:02

0

這取決於你想要做什麼。如果用戶和配置文件真實地爲一對一,那麼將整個配置文件替換爲另一個對象的整個想法有點多餘。如果您使用的是框架,保持整個操作的持久化上下文,那麼你可以只更新檔案對象並刷新值,如創建新的對象會因爲級聯的有點混亂。

但是,如果你的框架不會保留持久化上下文的身邊,那麼你就必須分離的實體已經被修改,你必須使用em.merge()你可以得到原來的實體(em.find)並複製屬性。IMO,這是乏味的,容易出錯的,並且沒有必要給出一個適當使用JPA的框架。這是更好的修改對象的持久化上下文,讓「自動更新實體」的事情做的工作(這很明顯,我的大風扇)。這需要一點習慣,但一旦你得到它,你永遠不會想回去。

在任何情況下,當調用em.flush()時,所有更改都將寫入JDBC連接,並且在事務完成時將提交連接中的掛起更改。

+0

我想我需要在互聯網上的某個地方的例子。 在GAE上使用JPA(我想使用:) – cscsaba 2010-06-27 19:19:58

+0

你提到的幾個術語在實踐中不太明確,這將是一個很好的例子。 我複製粘貼在我的實體的源代碼上面。 – cscsaba 2010-06-27 19:31:42

0

如何更新(替換)屬於用戶個人資料的實體?

由於您的關聯是雙向的,你必須UserProfile之間的管理鏈接的兩側。因此,「改變」一個用戶的配置文件將需要是這樣的:

User user = em.find(User.class, key); 

Profile profile = new Profile(); 
... 
user.setProfile(profile); 
profile.setUser(user); 

em.getTransaction().commit(); 

隨着JPA實現我所用,下面的查詢已經被上面的代碼執行:

INSERT INTO CPROFILE (ID) VALUES (?) 
    bind => [2] 
UPDATE CUSER SET CPROFILE_ID = ? WHERE (ID = ?) 
    bind => [2, 1] 
+0

你好帕斯卡,我已經試過你提到的這種方式沒有成功,我不知道什麼是錯的。 我要再試一次,謝謝 並感謝大家! – cscsaba 2010-06-28 07:47:53

+0

@ cscsaba242:這很奇怪。但我不是GAE/J JPA「支持」的專家,也許有一些我不知道的行爲的具體細節。 – 2010-06-28 14:13:58

0

我刪除了CascadeType的ALL和一切工作如我們預期,來這裏的代碼


......................... CPROFILE 
@Entity 
public class CProfile { 
     @Id 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     private Key id; 
     private String phone;

@OneToOne(mappedBy="profile") 
    private CUser User; 

......................... CUSER @Entity public class CUser { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private key id; 私人字符串電子郵件;

@OneToMany(mappedBy="user") 
private List<CPossibility> Possibilities = new ArrayList<CPossibility>(); 

@OneToOne 
@JoinColumn(name="cprofile_id") 
private CProfile profile; 

......................... CREATE ... CUser用戶= em.find(CUser.class,UserId_ ); ...
em.getTransaction()。begin(); 嘗試 { Profile_.setUser(User); User.setProfile(Profile_);

 em.persist(Profile_); 

     em.getTransaction().commit(); 
    } 
    catch(Exception e){GAEHelper.getLogger().warning("Exception:"+e.getMessage()+" "+e.getCause());}   
    finally { 
     if (em.getTransaction().isActive()) { 
      em.getTransaction().rollback(); 
     } 
    } 

    em.close(); 

    return true; 
} 

......................... UPDATE
... CUser用戶= em.find(CUser.class,用戶名_); ... em.getTransaction()。begin(); 嘗試 em.remove(User.getProfile());

 Profile_.setUser(User);    
     User.setProfile(Profile_); 

     em.persist(Profile_); 
     em.getTransaction().commit(); 
    } 

謝謝你們!

cscsaba