2011-04-20 55 views
7

我正在開發一個應用程序來幫助我的辦公室跟蹤和管理評論。在應用程序中,我將Hibernate 3.6.3的JPA 2.0作爲我的底層提供者。我也使用spring將持久化上下文注入到我的DAO中。我已經建立了這樣一個域,使得有一個評論,一個參與者和一個角色實體。實體管理器返回@OneToMany相關實體的重複副本

我遇到的問題是,如果參與者具有多個角色,當我從實體經理獲得審閱時,參與者列表中存在相同參與者(即相同ID)的重複副本。我還發現重複次數與數量角色直接相關(即,如果參與者有3個角色,則參與者在評論參與者列表中出現3次)

我以前使用過直接Hibernate,但這是我第一次使用JPA,所以我確定我配置了錯誤的東西。我只是不知道它是什麼。

下面是代碼:

評論:

@Entity 
public class Review extends BaseModel{ 

@ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER, optional=false) 
private Item item; 

@Column(name="ISNEW", nullable=false) 
private boolean isNew; 

@Enumerated(EnumType.STRING) 
@Column(name="STATUS", nullable=false) 
private ReviewStatus status; 

@Enumerated(EnumType.STRING) 
@Column(name="PHASE", nullable=false) 
private Phase phase; 

@Enumerated(EnumType.STRING) 
@Column(name="REVIEW_TYPE", nullable=false) 
private ReviewType reviewType; 

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) 
private List<Participant> participants; 

@OneToMany(cascade=CascadeType.ALL) 
private List<Defect> defects; 

@Column(name="START_DATE", nullable=false) 
private Date startDate; 

@Column(name="MEETING_DATE", nullable=false) 
private Date meetingDate; 

@Column(name="FINISH_DATE") 
private Date finishDate; 

@Column(name="DURATION", nullable=false) 
private Double duration; 

public Item getItem() 
{ 
    return item; 
} 
public void setItem(Item item) 
{ 
    this.item = item; 
} 
public List<Participant> getParticipants() { 
    return participants; 
} 
public void setParticipants(List<Participant> participants) { 
    this.participants = participants; 
} 
public List<Defect> getDefects() { 
    return defects; 
} 
public void setDefects(List<Defect> defects) { 
    this.defects = defects; 
} 
public boolean isNew() { 
    return isNew; 
} 
public void setNew(boolean isNew) { 
    this.isNew = isNew; 
} 
public Phase getPhase() { 
    return phase; 
} 
public void setPhase(Phase phase) { 
    this.phase = phase; 
} 
public Double getDuration() { 
    return duration; 
} 
public void setDuration(Double duration) { 
    this.duration = duration; 
} 
public ReviewStatus getStatus() { 
    return status; 
} 
public void setStatus(ReviewStatus status) { 
    this.status = status; 
} 
public Date getStartDate() { 
    return startDate; 
} 
public void setStartDate(Date startDate) { 
    this.startDate = startDate; 
} 
public Date getMeetingDate() { 
    return meetingDate; 
} 
public void setMeetingDate(Date meetingDate) { 
    this.meetingDate = meetingDate; 
} 
public Date getFinishDate() { 
    return finishDate; 
} 
public void setFinishDate(Date finishDate) { 
    this.finishDate = finishDate; 
} 
public ReviewType getReviewType() 
{ 
    return reviewType; 
} 
public void setReviewType(ReviewType reviewType) 
{ 
    this.reviewType = reviewType; 
} 

}

參與者:

@Entity 
public class Participant extends BaseModel{ 


     private Double inspectionTime; 

     @ManyToOne(cascade=CascadeType.ALL, optional=false) 
     private Person person; 

     @ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) 
     private Set<Role> roles; 

     public Double getInspectionTime() { 
      return inspectionTime; 
     } 
     public void setInspectionTime(Double preInspectionTime) { 
      this.inspectionTime = preInspectionTime; 
     } 
     public Person getPerson() { 
      return person; 
     } 
     public void setPerson(Person person) { 
      this.person = person; 
     } 
     public Set<Role> getRoles() { 
      return roles; 
     } 
     public void setRoles(Set<Role> roles) { 
      this.roles = roles; 
     } 

} 

角色:

@Entity 
public class Role extends BaseModel{ 
      @Column(nullable=false, unique=true) 
      private String name; 
      private String responsiblity; 

      public String getName() { 
       return name; 
      } 
      public void setName(String name) { 
       this.name = name; 
      } 
      public String getResponsiblity() { 
       return responsiblity; 
      } 
      public void setResponsiblity(String responsiblity) { 
       this.responsiblity = responsiblity; 
      } 

} 

基地:

@MappedSuperclass 
public abstract class BaseModel { 

    @Id 
    @GeneratedValue 
    private Long id; 

    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

} 

DataAccessObject它使用了EntityManager:

@Transactional(readOnly = false, propagation = Propagation.REQUIRED) 
public class ReviewDaoJpaImpl implements ReviewDao 
{ 


    @PersistenceContext 
    private EntityManager em; 

    public Review getReviewById(Long id) 
    { 
     return em.find(Review.class, id); 
    } 
} 

呼叫接收重複:

Review review = reviewDao.getReviewById(1776L); 
    List<Participant> participants = review.getParticipants(); 
    for (Participant participant : participants) 
    { 
     System.out.println(participant.getPerson().getName()); 
    } 

回答

12

問題是所謂的(N + 1個問題),並涉及參與者中角色的渴望獲取。

最簡單的方法是通過延遲加載來取代渴望獲取的處理。

+0

就是這樣。我很尷尬N + 1沒有出現在我對這個問題的任何搜索中。我想我沒有使用正確的關鍵字。謝謝你的幫助。我知道我做錯了什麼。 – Scott 2011-04-21 21:21:43

+0

你能解釋更多關於N + 1嗎? – Dejell 2013-06-20 22:01:39

+0

@Odelya Google for「n + 1 hibernate中的問題」第一擊是:http://stackoverflow.com/questions/97197/what-is-the-n1-selects-issue – Ralph 2013-06-21 12:37:01

3

Complete Reference to Hibernate Documentation

只要把Criteria.DISTINCT_ROOT_ENTITY它會在內部建立一套及複印件被自動刪除。

List result = session.createCriteria(Order.class) 
         .setFetchMode("lineItems", FetchMode.JOIN) 
         .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) 
         .list();