Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper Way to layer Spring JPA based DAO using Spring Boot Framework

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...

like image 229
PacificNW_Lover Avatar asked Apr 01 '15 00:04

PacificNW_Lover


People also ask

How do we use DAO layer in Spring data JPA?

In order to start leveraging the Spring Data programming model with JPA, a DAO interface needs to extend the JPA specific Repository interface - JpaRepository – in Spring's interface hierarchy. This will enable Spring Data to find this interface and automatically create an implementation for it.

What is DAO layer in Spring boot?

DAO stands for data access object. Usually, the DAO class is responsible for two concepts: encapsulating the details of the persistence layer and providing a CRUD interface for a single entity.

How does Spring boot integrate with JPA?

If we want to use JPA with MySQL database, we need the mysql-connector-java dependency. We'll also need to define the DataSource configuration. We can do this in a @Configuration class or by using standard Spring Boot properties. Spring Boot will automatically configure a data source based on these properties.

Which annotation is equivalent to auto create JPA class in DAO layer?

To activate the Spring JPA repository support, we can use the @EnableJpaRepositories annotation and specify the package that contains the DAO interfaces: @EnableJpaRepositories(basePackages = "com.


2 Answers

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>();
    }
}   
like image 109
shazin Avatar answered Oct 19 '22 04:10

shazin


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);

}
like image 14
daniel.eichten Avatar answered Oct 19 '22 05:10

daniel.eichten