2011-04-20 8 views
7

Estoy desarrollando una aplicación para ayudar a mi oficina a rastrear y administrar revisiones. En la aplicación, estoy usando JPA 2.0 con Hibernate 3.6.3 como mi proveedor subyacente. También estoy usando la primavera para inyectar el contexto de persistencia en mi DAO. Construí el dominio de modo que haya una Revisión, un Participante y una Entidad de función.Entity Manager devuelve copias duplicadas de una entidad relacionada con @OneToMany

El problema que tengo es que cuando recibo una revisión del administrador de la entidad hay copias duplicadas del mismo participante (es decir, la misma identificación) en la lista de participantes si el participante tiene más de un rol. También encontré que el número de duplicados está directamente relacionado con el número Roles (es decir, si un Participante tiene 3 Roles, el Participante aparece 3 veces en la lista de participantes de la Revisión)

He usado Hibernate directamente pero esto es La primera vez que uso JPA, estoy seguro de haber configurado algo incorrecto. Simplemente no sé qué es.

Aquí está el código:

opinión:

@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; 
} 

}

Participante:

@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; 
     } 

} 

Rol:

@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; 
      } 

} 

Base:

@MappedSuperclass 
public abstract class BaseModel { 

    @Id 
    @GeneratedValue 
    private Long id; 

    public Long getId() { 
     return id; 
    } 

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

} 

DataAccessObject que utiliza el 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); 
    } 
} 

llamada que recibe duplicados:

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

Respuesta

12

El problema se llama (N + 1 Problema) y se relaciona con la ansiosa búsqueda de Roles en Participant.

La manera más fácil de manejar sería reemplazar la búsqueda ansiosa por la carga lenta.

+0

Eso fue todo. Me avergüenza que N + 1 no haya aparecido en ninguna de mis búsquedas sobre el problema. Supongo que no estaba usando las palabras clave correctas. Gracias por tu ayuda. Sabía que estaba haciendo algo mal. – Scott

+0

¿Puedes explicar más sobre el N + 1? – Dejell

+0

@Odelya Google para "n + 1 problema en hibernación" primer golpe es: http://stackoverflow.com/questions/97197/what-is-the-n1-selects-issue – Ralph

3

Complete Reference to Hibernate Documentation

Criteria.DISTINCT_ROOT_ENTITY Sólo hay que poner se internamente y crear un conjunto de duplicados se eliminan automáticamente.

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