简体   繁体   中英

Projections in Hibernate

I have two class(Student and Mark) with one to many relationship in hibernate.

Mark Class

@Entity
@Table(name = "MARK")
public class Mark {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private int id;
private int sub1;
private int sub2;
@ManyToOne
@JoinColumn(columnDefinition = "studentid", referencedColumnName = "ID")
private Student student;

public int getId() {
    return id;
}

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

public int getSub1() {
    return sub1;
}

public void setSub1(int sub1) {
    this.sub1 = sub1;
}

public int getSub2() {
    return sub2;
}

public void setSub2(int sub2) {
    this.sub2 = sub2;
}

public Student getStudent() {
    return student;
}

public void setStudent(Student student) {
    this.student = student;
}

@Override
public String toString() {
    return "Mark [id=" + id + ", student=" + student + ", sub1=" + sub1
            + ", sub2=" + sub2 + "]";
}

    }

Student Class

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


@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
private int id;
private String fName;
private String lName;
@OneToMany
private List<Mark> marks;

public int getId() {
    return id;
}

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

public String getFName() {
    return fName;
}

public void setFName(String fName) {
    this.fName = fName;
}

public String getLName() {
    return lName;
}

public void setLName(String lName) {
    this.lName = lName;
}

public List<Mark> getMarks() {
    return marks;
}

public void setMarks(List<Mark> marks) {
    this.marks = marks;
}

@Override
public String toString() {
    return "Student [fName=" + fName + ", id=" + id + ", lName=" + lName
            + ", marks=" + marks + "]";
}

}

Test Method :

public void testMethod(){
    try{
        Criteria criteria = utilitiesDAO.getCriteria(Mark.class);
        criteria.createAlias("student", "student");
        ProjectionList projections = Projections.projectionList();
        projections.add(Projections.property("id"),"id");
        projections.add(Projections.property("sub1"),"sub1");
        projections.add(Projections.property("student"),"student");
                    projections.add(Projections.alias(Projections.property("student.fName"),"student.fName"));
        criteria.setProjection(projections);
        criteria.setResultTransformer(Transformers.aliasToBean(Mark.class));
        List ll = criteria.list();
        System.out.println(ll);
    }catch (Exception e) {
        e.printStackTrace();
    }
}

What I need is fname form Student with Mark details from database. Query generated by Hibernate criteria is

Hibernate: select this_.ID as y0_, this_.sub1 as y1_, student1_.fName as y2_ from MARK this_ inner join STUDENT student1_ on this_.student_ID=student1_.ID

and i'm getting exception :

   org.hibernate.PropertyNotFoundException: Could not find setter for student.fName on class
   at                     org.hibernate.property.ChainedPropertyAccessor.getSetter(ChainedPropertyAccessor.java:67)
   at org.hibernate.transform.AliasToBeanResultTransformer.initialize(AliasToBeanResultTransformer.java:118)
   at org.hibernate.transform.AliasToBeanResultTransformer.transformTuple(AliasToBeanResultTransformer.java:81)
   at org.hibernate.loader.criteria.CriteriaLoader.getResultColumnOrRow(CriteriaLoader.java:158)
   at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:639)
   at org.hibernate.loader.Loader.doQuery(Loader.java:829)
   at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:274)
   at org.hibernate.loader.Loader.doList(Loader.java:2542)
   at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2276)
   at org.hibernate.loader.Loader.list(Loader.java:2271)
   at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119)
   at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1716)
   at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)

You're doing it much harder than it should be, ad you have some errors as well.

First of all, the mapping is wrong. The OneToMany should be:

@OneToMany(mappedBy = "student")
private List<Mark> marks;

Second, you should really name your attributes better: firstName , lastName , and not fName , lName .

Your criteria query tries to add a projection for the property "student". But projections on an entity-type attribute are not supported by Criteria queries.

And it tries to use an AliasToBeanTransformer with the property sudent.fName of the object Mark. But this is not supported either. If you really want that, you should create a separate MarkDTO class, containing a firstName field. Returning partially populated detached entities from a query is a very bad idea, that will make it very confusing for the maintenance programmer (including you): you'll receive instances of Mark, but when asking them for the last name of their student, you'll get null and you'll wonder why.

Retrieveing just the first name instead of the whole Student entity likely won't bring any measurable performance improvement (especialy if your data set is so small that you can retrieve all the rows from the mark table), but makes your code more complex, and more fragile.

Just use the following HQL query, which will return the marks with their student, attached, in a single query:

select m from Mark m left join fetch m.student

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM