11

Am new to Spring Boot & JPA...

Let's say I have two entities mapped to two tables which are joined in a database.

Student-1------<-Course

Also, lets presume that the database is already created and populated.

This depicts that one student has many courses...

My Student Entity:

@Entity
public class Student {

    @OneToMany(mappedBy="student")
    private List<Courses> courses;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Student_Id")
    private long studentId;

    @Column(name = "Student_Name")
    private String studentName;

    protected Student() { }

    // Getters & Setters
}

My Course Entity:

@Entity
public class Course {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Course_Id")
    private long courseId;

    @Id
    @Column(name = "Student_Id")
    private long studentId;

    @ManyToOne
    @PrimaryKeyJoinColumn(name="Student_Id", referencedColumnName="Student_Id")
    private Student student;

    @Column(name = "Course_Name")
    private String courseName;

    // Getters & Setters

}

In Spring Boot's Tutorial Guides, it illustrates how to extend a CrudRepository interface, but it doesn't specify how to setup a Spring based DAO which contains custom finder methods which use HQL and EntityManager inside it.

Is the following DAO and DaoImpl correct?

public interface CourseDao {
    List<Course> findCoursesByStudentName(String studentName);
}

@Repository
public class CourseDaoImpl implements CourseDao {

    @PersistenceContext
    EntityManager em;

    public List<Course> findCoursesByStudentName(String studentName) {
        String sql = "select c.courseName" +
                     "from Course c, Student s " +
                     "where c.course_id = s.student_id " +
                     "and s.studentName = :studentName ";

        Query query = em.createQuery(sql);
        query.setParameter("studentName", studentName);
        return query.getResultList();
    }
}   

And then in the client code, for example, in the main class:

 public class Application {

    @Autowired
    CustomerDao dao;

    public static void main (String args []) {
        List<Course> courses = dao.findCoursesByStudentName("John");
    }   
 }

Is this the standard way to use HQL inside Spring DAOs ? I've seend examples of the @Transactional annotation being prepended to the DAO class's impl (e.g. CustomerDAOImpl) ?

Please let me know if this is the write way to structure my Spring Boot app or am I supposed to extend / add to the CrudRepository only?

If someone could correct my example and point me to a URL which talks about HQL using Entities that are joined, I would be very grateful.

The Spring Boot guides didn't depict joins or DAOs - I just need to learn how to properly create finder methods which emulate select statement which return lists or data structures.

Thanks for taking the time to read this...

2 Answers 2

14

If I understood your question correct you do have two questions:

  1. How to create a DAO and DAOImpl?
  2. Where to put your Transaction annotations?

In regards to the first question I want to point out that this is a question in regards to spring-data-jpa using Hibernate as a JPA provider, not spring-boot.

Using Spring Data I usually skip completely to create a DAO but directly use a Custom Repository extending a standard one like CrudRepository. So in your case you don't even have to write more code than:

@Repository
public interface StudentRepository extends CrudRepository<Student, Long> {

    List<Student> findByStudentName(String studentName);

}

Which will be sufficient and Spring Data will take care of filling it with the correct implementation if you use

@Autowired
StudentRepository studentRepo; 

in your service class. This is where I also usually annotate my methods with @Transactional to make sure that everything is working as expected.

In regards to your question about HQL please look into the spring data jpa documentation, which points out that for most of the cases it should be sufficient to stick to proper named methods in the interface or go for named queries (section 3.3.3) or use the @Query annotation (section 3.3.4) to manually define the query, e.g. should work (didn't tried):

@Repository
public interface @CourseRepository extends CrudRepository<Course, Long> {

    @Query("select c.courseName from Course c, Student s where c.course_id = s.student_id and s.studentName = :studentName")
    public List<Course> findCoursesByStudentName(String studentName);

}
Sign up to request clarification or add additional context in comments.

3 Comments

which is better? JPA or Cruid repository? can we just use repository? last time i used hibernate there ware spring 2.5 and hibernate 3, not just i forgot what it was all about, i also didn't use these feature, before newly seeing them on youtube...
JPARepository is actually inheriting from CRUDRepository so it is a specific type to deal with JPA Pojos. See docs.spring.io/spring-data/jpa/docs/current/api/org/…
thanks a lot, '<S extends T> S saveAndFlush(S entity)' :O doesn't save operation within the crud, perform all the saves changes on database?
2

If you annotate your CourseDaoImpl with @Transactional (Assuming your have defined JpaTransactionManager correctly) You can just retrieve the Student with the matching name and call the getCourses() method to lazy load the Courses attached to that student. Since findCoursesByStudentName will run within a Transaction it will load the courses just fine.

@Repository
@Transactional(readOnly=true)
public class CourseDaoImpl implements CourseDao {

    @PersistenceContext
    EntityManager em;

    public List<Course> findCoursesByStudentName(String studentName) {
        String sql = "select s " +
                     "from Student s " +
                     "where s.studentName = :studentName ";

        Query query = em.createQuery(sql);
        query.setParameter("studentName", studentName);
        User user = query.getSingleResult();
        if(user != null) {
            return user.getCourses();
        }

        return new ArrayList<Course>();
    }
}   

2 Comments

shazin, thanks for responding... Is this the standard way to do HQL? You are doing a select of Students and not the join? I am confused... Also, why the readOnly=true? What do you mean define JpaTransactionManager correctly? How would you do that in Spring Boot? Why not use the CrudRespository? What I am seeking is the standard way to do things... Thanks for your help.
Where is this User class / object ref defined? Did you mean Student?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.