2011-02-03 26 views
9

Tôi có lớp DAO trừu tượng sử dụng các loại tham số E (Pháp nhân) và K (Khóa chính). Trong mọi thực thể tôi có @NamedQuery. Tôi muốn tự động gọi truy vấn được đặt tên này mà không biết tên chính xác và tên thông số của nó.Tóm tắt các truy vấn được đặt tên trong JPA DAO trừu tượng

Như một ví dụ, hãy tưởng tượng thực thể sau City

@Entity(name="CITY") 
@NamedQuery(
    name="findCityByname", 
    query="FROM CITY c WHERE name = :CityName" 
) 
public class City { 
    // ... 
} 

và điều này CityDao

public class CityDao extends AbstractDao<City, Long> { 
    public CityDao() { 
     super(City.class); 
    } 
} 

Làm thế nào tôi nên thực hiện phương pháp findByName() trong AbstractDao vì vậy mà tôi không cần phải biết chính xác tên và tên thông số?

public abstract class AbstractDao<E, K> implements Dao<E, K> { 

    @PersistenceContext 
    protected EntityManager entityManager; 
    protected Class<E> entityClass; 

    protected AbstractDao(Class<E> entityClass) { 
     this.entityClass = entityClass; 
    } 

    @Override 
    public E findByName(String name) { 
     try { 
      return (E) entityManager 
       .createNamedQuery("findCityByName") 
       .setParameter("CityName", name) 
       .getSingleResult(); 
     } catch(Exception e) { 
      return null; 
     } 
    } 

    // ... 
} 

Trả lời

11

Quy ước đặt tên cho truy vấn được đặt tên thường là <Entity Name>.findBy<PropertyAndAnotherProperty>, "City.findByName" trong ví dụ của bạn, vì vậy tôi sẽ cố gắng thay đổi các truy vấn được đặt tên theo mẫu này. Tham số cho truy vấn này sau đó cũng phải có cùng tên hoặc bạn có thể sử dụng các tham số vị trí. phương pháp tìm của bạn sau đó sẽ biến thành

@Override 
public E findByName(String name) { 
    E entity = null; 
    try { 
     return (E)entityManager.createNamedQuery(myClass.getSimpleName() + ".findByName") 
           .setParameter("name", name) 
           .getSingleResult(); 
    } catch (Exception ex) { 
     return null; 
    } 
} 
1

Phương pháp đơn giản nhất là để vượt qua tên của truy vấn để các nhà xây dựng của DAO trừu tượng:

public DaoAbstreact(Class myClass, String findByNameQueryName) { 
    this.myClass = myClass; 
    this.findByNameQueryName = findByNameQueryName; 
} 

Sau đó xác định một chuỗi thức public static ở thành phố để giữ tên:

public class ConcreteCityDao<City,Long> extends DaoAbstreact {  
    ConcreteCityDao(){ 
     super(City.class, City.FIND_BY_NAME_QUERY_NAME)); 
    } 
} 

Hoặc bạn có thể khai báo DaoAbstreact dưới dạng trừu tượng và sau đó có phương pháp như sau:

public abstract String getFindByNameQueryName(); 

Và thực hiện điều đó trong ConcreteCityDao.

Cuối cùng bạn cũng có thể giới thiệu một đếm:.

public enum NamedEntityType { 
    CITY(City.class, "findCityByname"), 
    PERSON(Person.class, "findPersonByname"); 

    private final Class<?> entityClass; 

    private final String findByNameQueryName; 

    private NamedEntityType(Class<?> entityClass, String findByNameQueryName) { 
     this.entityClass = entityClass; 
     this.findByNameQueryName = findByNameQueryName; 
    } 

    public Class<?> getEntityClass() { 
     return entityClass; 
    } 

    public String getFindByNameQueryName() { 
     return findByNameQueryName; 
    } 
} 

Sau đó DAO của bạn có thể xác định loại từ lớp đều đạt trong Để đảm bảo bạn đừng quên thêm một thực thể để kiểu liệt kê, bạn có thể làm cho mỗi thực thể thực hiện một giao diện với một phương thức getNamedEntityType(). Sau đó, bạn có thể chỉ định rằng DAO chung trừu tượng của bạn sẽ chỉ chấp nhận các thực thể thực hiện giao diện đó.

+0

nó sẽ đưa ra khái niệm 'Tôi muốn sống với loại khái niệm ... –

0

Cách hiển nhiên sẽ là chuyển giá trị từ các lớp học cụ thể để các lớp cha trừu tượng sử dụng abstract phương pháp

public abstract class AbstractDao<E, K extends Serializable> implements Dao <E, K> { 
    ... 
    protected abstract String getFindByNameQueryName(); 

    @Override 
    public E findByName(String EntityStr) { 
     ... entityManager.createNamedQuery(getFindByNameQueryName()) ... 
    } 
} 

@Override 
public class ConcreteCityDao<City,Long> extends DaoAbstreact{ 
    ... 
    protected String getFindByNameQueryName() { 
     return "findCityByName"; 
    } 
} 

hoặc như một đối số nhà xây dựng:

public abstract class AbstractDao<E, K extends Serializable> implements Dao<E, K> { 
    public AbstractDao(Class<E> myClass, String findByNameQueryName) { ... } 
    ... 
} 

@Override 
public class ConcreteCityDao<City, Long> extends DaoAbstreact{ 
    public ConcreteCityDao() { 
     super(City.class, "findCityByName"); 
    } 
} 

Mặc dù điều này đòi hỏi đặt tên nhất quán của các tham số truy vấn cho các thực thể khác nhau.

Cũng lưu ý những cải tiến nhỏ trong các đoạn mã này.

0

gì về cơ bản bạn dường như muốn là để chú thích các chú thích để xác định các truy vấn tên, theo cách như vậy mà bạn có thể lập trình khám phá những gì các "findByName" truy vấn là (và có thể các truy vấn khác).

Vì điều này là không thể trong Java, bạn có thể sử dụng thực tế là @NamedQuery hỗ trợ gợi ý truy vấn, được định nghĩa là nhà cung cấp cụ thể. Các gợi ý không xác định được bỏ qua. Bạn có thể thêm dữ liệu của riêng mình tại đây, rằng DAO chung có thể đọc lại từ entityClass:

@NamedQuery(
    name="findCityByname", 
    query="FROM CITY c WHERE name = :CityName", 
    [email protected](name="genericDAO.type", value="findByName") 
) 
Các vấn đề liên quan