2016-06-26 35 views
5

Tôi đã tìm thấy một vài hướng dẫn về cách xây dựng một DAO Hibernate với generics, nhưng tất cả đều sử dụng EntityManager thay vì một SessionFactory. Câu hỏi của tôi là làm thế nào để xây dựng một DAO với Generics sử dụng SessionFactory. Tôi có bên dưới cho đến nay:Làm thế nào để thực hiện DAO Hibernate với generics

Interface:

public interface GenericDao<T> { 

    public void save(T obj); 
    public void update(T obj); 
    public void delete(T obj); 
    public T findById(long id); 
} 

Class:

@Repository 
public class GenericDaoImpl<T> implements GenericDao<T> { 

    @Autowired 
    private SessionFactory sessionFactory; 

    public void save(T obj) { 
     Session session = sessionFactory.openSession(); 
     Transaction tx = null; 
     try { 
      tx = session.beginTransaction(); 
      session.save(obj); 
      tx.commit(); 
     } catch (HibernateException e) { 
      if(tx != null) 
       tx.rollback(); 
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

    } 

    public void update(T obj) { 
     Session session = sessionFactory.openSession(); 
     Transaction tx = null; 
     try { 
      tx = session.beginTransaction(); 
      session.update(obj); 
      tx.commit(); 
     } catch (HibernateException e) { 
      if(tx != null) 
       tx.rollback(); 
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

    } 

    public void delete(T obj) { 
     Session session = sessionFactory.openSession(); 
     Transaction tx = null; 
     try { 
      tx = session.beginTransaction(); 
      session.delete(obj); 
      tx.commit(); 
     } catch (HibernateException e) { 
      if(tx != null) 
       tx.rollback(); 
      e.printStackTrace(); 
     } finally { 
      session.close(); 
     } 

    } 

    public T findById(long id) { 
     // ?? 
     return null; 
    } 

tôi không chắc chắn làm thế nào để đi về findById sử dụng Generics. Tôi tin rằng các phương pháp khác là đúng, nhưng đúng với tôi nếu tôi sai.

CÂU HỎI THƯỜNG GẶP: Sử dụng EntityManager có lợi hơn việc sử dụng SessionFactory? Tôi đã thấy một vài bài viết về chủ đề này, nhưng muốn có thêm một vài ý kiến.

+0

Trong Java, Generics được thực hiện bằng cách xóa và tham số kiểu chính thức của bạn 'T' trở thành' Object' tại thời gian chạy. Nói cách khác, tại thời gian chạy kiểu 'T' không tồn tại. Bất kỳ phương thức chung nào trả về một cá thể 'T' mới được tạo ra sẽ do đó yêu cầu một mã thông báo kiểu thời gian chạy mà phương thức có thể sử dụng để xác định một cách phản ánh kiểu cá thể mà nó sẽ cần phải tạo ra. Một chữ ký thực tế hơn cho 'findById (...)' là do đó 'public T findById (lớp lớp, id dài)'. – scottb

+0

@scottb để mã thông báo Lớp sẽ được sử dụng để xác định loại đối tượng mà phương thức cần trả về? Làm thế nào tôi sẽ đi về điều này một cách chính xác?Với các ví dụ 'EntityManager', tôi thấy' entityManager.find (type.class, id); 'nhưng tôi không chắc chắn về cách làm điều này với' SessionFactory'. –

+0

Nếu kiểu bạn cần trả lại có một hàm tạo không có đối số, thì cách dễ nhất có thể để tự động đúc một thể hiện mới của một kiểu tùy ý 'T' sẽ sử dụng phương thức' newInstance() 'của' Class ', ví dụ. 'T myObj = class.newInstance();'. Nếu không, bạn có thể cần phải sử dụng sự phản chiếu thông qua đối tượng 'Class ' để gọi một hàm tạo thích hợp với các đối số. Trong một phương thức như vậy, 'lớp' trong lớp' Lớp ' đóng vai trò của một * loại thời gian chạy *. Trong Java, đôi khi chúng cần thiết một cách chính xác vì các kiểu generic không tồn tại trong thời gian chạy. – scottb

Trả lời

5

Bạn cần có quyền truy cập vào số Class<T> từ bên trong phương thức đó. Bạn có hai lựa chọn, bạn có thể vượt qua Class<T> vào phương pháp:

public T findById(long id, Class<T> clazz) { 
    // method implementation 
} 

Hoặc bạn có thể vượt qua Class<T> vào constructor của lớp để sử dụng trong phương pháp:

@Repository 
public class GenericDaoImpl<T> implements GenericDao<T> { 

    private Class<T> clazz; 

    protected GenericDaoImpl(Class<T> clazz) { 
     this.clazz = clazz; 
    } 

    // other methods omitted 

    public T findById(long id) { 
     // method implementation 
    } 
} 

Và lớp con sẽ vượt qua lớp học của họ vào lớp cha:

public class UserDao extends GenericDaoImpl<User> { 
    public UserDao() { 
     super(User.class); 
    } 
} 

Sau đó, sử dụng trường hợp clazz bạn có thể nhận thực thể theo phương pháp chung bằng cách sử dụng Session#get phương pháp:

T entity = session.get(clazz, id); 

Xem các câu hỏi sau đây để biết thêm thông tin:


Theo như câu hỏi phụ, các EntityManager là một phần của JPA (Ja và Persistence API). Phát triển ứng dụng của bạn bằng cách sử dụng đặc tả Java API thay vì API Hibernate cho phép ứng dụng của bạn không trở nên phụ thuộc vào Hibernate. Điều này cho phép bạn chuyển đổi giữa các triển khai JPA phổ biến như Hibernate, OpenJPA hoặc TopLink mà không cần thực hiện và thay đổi mã của bạn.

This question có thêm thông tin về sự khác biệt.

+0

Cảm ơn bạn! Một câu hỏi phụ khác - Có lý do nào để sử dụng 'EntityManager' trên' SessionFactory' và ngược lại không? Hay cả hai đều làm chủ yếu điều tương tự? –

+0

Không cần thêm dòng 'super (User.class);'. Lớp chung trừu tượng có thể tìm ra đối số kiểu của các lớp con của nó, như được thấy ở đây: https://github.com/acdcjunior/acdcjunior-github-io-example-projects/blob/master/spring-mvc-jpa-mockito -piloto/src/main/java/net/acdcjunior/piloto/cơ sở hạ tầng/jpa/JpaAbstractRepository.java # L43 – acdcjunior

+0

@JakeMiller 'EntityManager' là JPA,' SessionFactory' là Hibernate (triển khai JPA). Chúng không giống nhau. 'EntityManager' (JPA) là' Session' (Hibernate) là 'EntityManagerFactory' (JPA) là' SessionFactory' (Hibernate). Thông thường, chúng tôi thích JPA hơn. Nhưng nếu bạn không có kế hoạch bao giờ thay đổi việc thực hiện từ Hibernate sang khác (chẳng hạn như TopLink), nó không thành vấn đề (ý tôi là, trong trường hợp này, hãy sử dụng bất cứ thứ gì bạn thích). – acdcjunior

Các vấn đề liên quan