2014-12-04 68 views
0

當我有一個包含在一個方式我以前從來沒有遇到另一個實體的關係的實體,而我得到一個例外:「org.hibernate.exception.ConstraintViolationException:可能不執行聲明「。休眠 - ConstraintViolation長期以實體

父實體稱爲「發佈」。帖子可以包含多個關鍵字實體。關鍵字實體的值是唯一的,也就是說,如果兩個帖子包含相同的關鍵字,則這兩個帖子引用相同的關鍵字實體。

我的思維過程是有很多帖子,每個引用的關鍵字,任何一個關鍵字可以由多個帖子引用,所以它應該是一個@ManyToMany關係。顯然,這不起作用。檢查數據庫顯示它在開始失敗之前成功保留了幾個帖子。只要所有關鍵字都是唯一的,這似乎是好的,但我認爲,只要它試圖用已經被另一篇文章引用的關鍵字來保存文章,它就會消失。不知道如何解決這個問題。

這裏是班級的樣子(短版):

帖子:

@Entity 
public class Post implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "post_id_seq") 
    @SequenceGenerator(name = "post_id_seq", sequenceName = "post_id_seq", allocationSize = 1) 
    private Long id; 

    @ElementCollection(fetch = FetchType.EAGER) 
    @ManyToMany(cascade = CascadeType.ALL) 
    private Set<Keyword> keywords = new HashSet<>(); 
} 

關鍵字:

@Entity 
public class Keyword implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "keyword_id_seq") 
    @SequenceGenerator(name = "keyword_id_seq", sequenceName = "keyword_id_seq", allocationSize = 1) 
    private Long id; 

    @Column(name = "KEYWORD_VALUE") 
    private String value; 
    private int count = 1; 
} 

UPDATE:

這裏是我使用的代碼在我的服務類中添加一個關鍵字的職位。基本上我有一個Post對象已經有關鍵字填充(請求通過AJAX從Web前端進來,並且Spring自動將它解組爲Post對象)。我必須遍歷每個關鍵字,並查看具有相同值的實體是否已存在於持久性中。如果是這樣,請增加該關鍵字的計數,合併它,然後將該實體添加到將取代請求中出現的Set的集合。如果它不存在,我只使用請求中的關鍵字。以前,我是不節能/將它們添加到郵政和堅持後前獨立合併關鍵詞,但我開始的錯誤,指出:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.saic.jswe.clients.swtc.domain.social.Keyword

不管怎麼說,這是我的服務代碼:

public void addPost(Post post){ 
Set<Keyword> keywords = new HashSet<>(); 
     for (Keyword keyword : post.getKeywords()) { 
      Keyword persistedKeyword = keywordDao.findByValue(keyword.getValue()); 
      if (persistedKeyword != null) { 
       persistedKeyword.setCount(persistedKeyword.getCount() + 1); 
       keywordDao.merge(persistedKeyword); 
       keywords.add(persistedKeyword); 

      } else { 
       keywordDao.persist(keyword); 
       keywords.add(keyword); 
      } 
     } 
     post.setKeywords(keywords); 
postDao.persist(post); 
} 

另外,在我測試的過程中,當我收到這個錯誤時,它只是一個試圖添加一個測試Post對象的線程。

檢查日誌,這裏是實際約束衝突:

rg.postgresql.util.PSQLException: ERROR: insert or update on table "keyword" violates foreign key constraint "fk_3tcnkw7v196mudsgmy3nriibl" Detail: Key (id)=(1) is not present in table "post".

嗯......每上面的代碼,它應該只被添加到一個關鍵字對象的引用一個ID,如果它其實並在持久中找到它。通過請求進入Post對象的關鍵字對象應該都具有空ID,因爲它們還沒有被保留。

+0

錯誤消息應該包含約束名稱。使用它你可以找出違反了什麼限制條件。 – talex 2014-12-04 16:22:15

+0

我想你添加關鍵字不檢查其存在。或者有多個線程添加關鍵字。 – talex 2014-12-04 16:23:28

+0

請檢查我的更新在原來的問題 – Bal 2014-12-04 17:00:59

回答

0

我發現問題發揮的地方。正在創建一個名爲「post_keywords」的連接表。它有2列,一個叫做「post」,一個叫「關鍵字」。每一行都代表帖子的ID以及該帖子中包含的關鍵字的ID。如果帖子中有多個關鍵字,則帖子列中可能有重複的條目。然而,只要不同的郵政實體試圖引用已經使用的關鍵字,就會抱怨該ID已經存在。這裏的視覺效果如下:

post | keyword 
-----+-------- 
1 | 1 
1 | 2 
1 | 4 
2 | 3 
2 | 4 <--- this would be a problem since keyword 4 is already related to post 1 

所以我對JPA的理解/理解相當薄弱,但我只需要真正的基本關係。鑑於我瞭解問題發生的地點,我決定退出遊戲並嘗試並開始閱讀。

一分鐘,我以爲我找到了解決方法只使用一個一對多的關係,因爲我沒有必要關心或需要的關鍵字實體直接知道哪些帖子引用它。然而,這是不正確的。我可以讓這些代碼無誤地執行,但是我最終得到的每個關鍵字只能由一個實體擁有。由於每個帖子都試圖引用該關鍵字,因此它會覆蓋此關鍵字的以前所有權。無論如何,我確實需要一個ManyToMany關係。我最終找到了示例(http://en.wikibooks.org/wiki/Java_Persistence/ManyToMany),其中顯示了多個子實體引用同一個父實體的表,因此我只在我的代碼和中提琴中實現了相同的JPA屬性,它工作正常。以下是代碼現在的樣子:

@Entity 
public class Post implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "post_id_seq") 
    @SequenceGenerator(name = "post_id_seq", sequenceName = "post_id_seq", allocationSize = 1) 
    @Column(name="POST_ID") 
    private Long id; 

    @ManyToMany(fetch = FetchType.EAGER) 
    @JoinTable(
     name="POST_KEYWORD", 
     joinColumns={@JoinColumn(name="POST_ID", referencedColumnName="POST_ID")}, 
     inverseJoinColumns={@JoinColumn(name="KEYWORD_ID", referencedColumnName="ID")}) 
    private Set<Keyword> keywords = new HashSet<>(); 
}