2011-02-03 34 views
9

我有一個抽象的DAO類,它使用參數化類型E(實體)和K(主鍵)。在每個實體中,我都有一個@NamedQuery。我想動態調用這個命名查詢而不知道它的確切名稱和參數名稱。抽象抽象JPA中的命名查詢DAO

作爲一個例子,假設下面的實體City

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

CityDao

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

我應該如何實現findByName()方法AbstractDao,這樣我不需要知道確切的名稱和參數名稱?

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

    // ... 
} 

回答

11

命名查詢的命名約定通常是<Entity Name>.findBy<PropertyAndAnotherProperty>,在您的示例中爲「City.findByName」,所以我會嘗試更改命名查詢以遵循此模式。此查詢的參數應該也具有相同的名稱,或者可以使用位置參數。然後你找到方法將變成

@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

最簡單的方法是將查詢的名稱傳遞給抽象DAO的構造函數:

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

然後定義在城市公共靜態最終字符串來保存的名字:

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

另外,你可以聲明DaoAbstreact爲抽象,然後有一個像這樣的方法:

public abstract String getFindByNameQueryName(); 

並在ConcreteCityDao中實現。

最後,您還可以引入一個枚舉:

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

那麼你的DAO可以確定在傳遞的類的類型,以確保你不要忘了實體添加到枚舉可以使每個實體使用getNamedEntityType()方法實現接口。然後,您可以指定您的抽象通用DAO將只接受實現該接口的實體。

+0

它敲打概念「我想住的理念排序斑點的... – 2011-02-03 14:44:53

0

最顯而易見的方法是使用abstract方法

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"; 
    } 
} 

或作爲構造函數參數傳遞從具體類的抽象超值:

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

雖然這需要的查詢參數一致​​的命名爲不同的實體。

另請注意這些代碼片段中的小改進。

0

什麼,你基本上似乎要被標註定義命名查詢註釋,以這樣的方式,你可以通過編程發現「findByName」查詢是什麼(可能其他查詢)。

由於這在Java中不可行,所以您可以使用@NamedQuery支持查詢提示的事實,該提示被定義爲供應商特定的。未知的提示被忽略。您可以在這裏添加你自己的數據,該通用DAO可以從entityClass回讀:

@NamedQuery(
    name="findCityByname", 
    query="FROM CITY c WHERE name = :CityName", 
    [email protected](name="genericDAO.type", value="findByName") 
)