ResultTransformer in Hibernate return null

brakebg picture brakebg · Jun 21, 2011 · Viewed 8.9k times · Source

I'm using ResultTransformer to select only particular properties from entity, just i don't need all properties from entity. But the problem i faced is when a property is "one-to-many". Here is a simple example.

@Entity
@Table(name = "STUDENT")
public class Student
{

private long studentId;
private String studentName;
private List<Phone> studentPhoneNumbers = new ArrayList<Phone>();

@Id
@GeneratedValue
@Column(name = "STUDENT_ID")
public long getStudentId()
{
  return this.studentId;
}
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(name = "STUDENT_PHONE", joinColumns = {@JoinColumn(name = "STUDENT_ID")}, inverseJoinColumns = {@JoinColumn(name = "PHONE_ID")})
public List<Phone> getStudentPhoneNumbers()
{
  return this.studentPhoneNumbers;
}
@Column(name = "STUDENT_NAME", nullable = false, length = 100)
public String getStudentName()
{
  return this.studentName;
}

Here is the class used by ResultTransformer for storing the selected properties.

public class StudentDTO
{
private long m_studentId;
private List<Phone> m_studentPhoneNumbers = new ArrayList<Phone>();
.. 
constructors and getters and setters..

And finally the Criteria code

 Criteria criteria = session.createCriteria(Student.class)
    .setProjection(Projections.projectionList()
      .add(Projections.property("studentId"), "m_studentId")
      .add(Projections.property("studentPhoneNumbers"), "m_studentPhoneNumbers"))
    .setResultTransformer(Transformers.aliasToBean(StudentDTO.class));


  List list = criteria.list();
  StudentDTO p = (StudentDTO) list.get(0);

So, after i get StudentDTO object , only studenId is available, studentPhoneNumber is null .. Does it mean ResultTransformer does not work with any relationships ? or my way is wrong Any suggestions?

Thanks

Answer

OTrain picture OTrain · Aug 12, 2011

I have run into this problem before. The transformers in hibernate generally lead to frustration. You can do a manual assignment as is suggested, or you can map the DTO class to the same table using hibernate. Just add the same annotation to your StudentDTO class as the Student class and then load it like normal. So student DTO would be:

@Entity
@Table(name = "STUDENT")

public class StudentDTO
{

private long studentId;
private String studentName;
private List<Phone> studentPhoneNumbers = new ArrayList<Phone>();

@Id
@GeneratedValue
@Column(name = "STUDENT_ID")
public long getStudentId()
{
  return this.studentId;
}
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(name = "STUDENT_PHONE", joinColumns = {@JoinColumn(name = "STUDENT_ID")}, inverseJoinColumns = {@JoinColumn(name = "PHONE_ID")})
public List<Phone> getStudentPhoneNumbers()
{
  return this.studentPhoneNumbers;
}

Just leave out what you do not want to load.