2015-06-11 68 views
0

我有新聞實體和評論實體。我想用0條評論創建新聞,然後在此新聞中添加一些評論。JPA添加子女記錄 - 父母有3個副本

在數據庫我有新聞信息和news_id列在COMMENTS表中的新聞。

News.java:

@Entity 
@Table(name = "NEWS") 
public class News implements Serializable{ 
    /** 
    * serialVersionUID 
    */ 
    private static final long serialVersionUID = 883279937885116359L; 
    /** 
    * News id 
    */ 
    @Id 
    @GeneratedValue(generator = "seq") 
    @SequenceGenerator(name="seq", sequenceName="NEWS_SEQ",allocationSize=1) 
    @Column(name = "NEWS_ID", nullable = false, unique = true) 
    private Long id; 
    /** 
    * News short text 
    */ 
    @Column(name = "SHORT_TEXT") 
    private String shortText; 
    /** 
    * News full text 
    */ 
    @Column(name = "FULL_TEXT") 
    private String fullText; 
    /** 
    * News title 
    */ 
    @Column(name = "TITLE") 
    private String title; 
    /** 
    * News creation date 
    */ 
    @Column(name = "CREATION_DATE") 
    private Date creationDate; 
    /** 
    * News modification date 
    */ 
    /** 
    * News comments 
    */ 
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval= true, fetch = FetchType.EAGER) 
    @JoinColumn(name = "NEWS_ID") 
    private List<Comment> comments; 

Comment.java:

@Entity 
@Table(name = "COMMENTS") 
public class Comment implements Serializable{ 
    /** 
    * serialVersionUID 
    */ 
    private static final long serialVersionUID = -5697896094322498108L; 
    /** 
    * Comment id 
    */ 
    @Id 
    @GeneratedValue(generator = "seq") 
    @SequenceGenerator(name="seq", sequenceName="COMMENTS_SEQ",allocationSize=1) 
    @Column(name = "COMMENT_ID", nullable = false, unique = true) 
    private Long id; 
    /** 
    * Comment text 
    */ 
    @Column(name = "COMMENT_TEXT") 
    private String commentText; 
    /** 
    * Comment creation date 
    */ 
    @Column(name = "CREATION_DATE") 
    private Date creationDate; 
    /** 
    * Id of the news which the comment is added to 
    */ 
    @Column(name = "NEWS_ID") 
    private Long newsId; 

我有這樣的代碼:

  News news = new News(); 

      news.setTitle("qwerty"); 
      news.setShortText("qwerty"); 
      news.setFullText("qwerty"); 

      jpaNewsDAO.add(news); 
      news = jpaNewsDAO.findById(news.getId());//everything is fine here 
                // 0 comments 
      Comment comment = new Comment(null,"qwerty",new Date(),news.getId()); 
      jpaCommentDAO.add(comment); 
      news = jpaNewsDAO.findById(news.getId()); 

但是news.comments後有3項與副本(即使有相同的ID)的評論,我不明白爲什麼。 DB中只有一個這樣的評論。

添加評論:

@Override 
    public Long add(Comment entity) throws DAOException { 
     EntityManager manager = null; 
     EntityTransaction transaction; 
     try { 
      manager = managerFactory.createEntityManager(); 
      transaction = manager.getTransaction(); 
      transaction.begin(); 
      entity.setId(null); 
      manager.persist(entity); 
      manager.flush(); 
      transaction.commit(); 
     } catch (PersistenceException e) { 
      throw new DAOException(e); 
     } finally { 
      closeManager(manager); 
     } 
     return entity.getId(); 
    } 

添加消息:

@Override 
    public Long add(News entity) throws DAOException { 
     EntityManager manager = null; 
     EntityTransaction transaction; 
     try { 
      manager = managerFactory.createEntityManager(); 
      transaction = manager.getTransaction(); 
      transaction.begin(); 
      entity.setId(null); 

      List<Comment> comments = new ArrayList<Comment>(); 
      if (entity.getComments()!= null) { 
       for (Comment comment : entity.getComments()) { 
        comments.add(manager.find(Comment.class, comment.getId())); 
       } 
      } 
      entity.setComments(comments); 

      manager.persist(entity);//add 
      manager.flush(); 
      transaction.commit(); 
     } catch (PersistenceException e) { 
      throw new DAOException(e); 
     } finally { 
      closeManager(manager); 
     } 
     return entity.getId(); 
    } 

那麼,爲什麼我有意見的副本?

+0

你的添加方法看起來很奇怪。你爲什麼重新將評論添加到新聞中?如果您保存新聞,JPA將保存評論。從你身邊無需額外的工作。此外評論應該有一個參考新聞不僅newsid。通過這種方式,您可以充分利用JPA – Konstantin

+1

發佈jpaNewsDAO findById()方法的代碼,因爲這很可能出現問題所在。 –

+0

和你的flush()調用是不必要的,刷新發生在commit(即緊接着的語句)之後。 –

回答

1

問題是由於新聞和評論之間的關係標記爲EAGER。有關這是爲什麼更多信息的情況下在這裏看到:

Hibernate Criteria returns children multiple times with FetchType.EAGER

可以標記關係,懶惰,這將防止問題。通常情況下,最佳實踐是以這種方式定義關係,並通過查詢提示或JPA 2.1的新「實體圖」功能,按照給定用途的要求快速提取關係。

https://blogs.oracle.com/theaquarium/entry/jpa_2_1_entity_graphs

現在,你可以簡單地添加下面一行在你的DAO:

news.getComments()大小()。

這將強制延遲收集加載。它顯然將在您的Web層中可用。

0

移動事務開始/提交更高,並在其評論請確保您的新聞對象點,反之亦然

Transaction transaction = beginTransaction(); //start a transaction 
News news = new News();  
news.setTitle("qwerty"); 
news.setShortText("qwerty"); 
news.setFullText("qwerty"); 

Comment comment = new Comment(null,"qwerty",new Date(),news); //note news not news.getId() 

news.addComment(comment); 

//You now have a correct "graph" news points at comment and comment points at news 

//persist 
jpaNewsDAO.add(news); 

commitTransaction(transaction); //commit 

//Hibernate will now have persisted both Comment and News for you 

只添加依舊沒有別的需要處理異常你曾經認爲適合

@Override 
public Long add(News entity) throws DAOException { 

    manager.persist(entity); 
} 
+0

我不能做它,因爲它的MVC應用程序,所以這段代碼是從單元測試。此操作將在不同的控制器中工作。 –

+0

我改變了newsId的消息,但仍然有這個問題。我更改列表爲設置,但其愚蠢=) –

+0

是findbyId瑣碎或您是否嘗試閱讀評論表單數據庫在同一時間? – Konstantin