2011-02-03 19 views
9

私は、パラメータ化された型E(Entity)とK(主キー)を使用する抽象DAOクラスを持っています。すべてのエンティティで私は@NamedQueryを持っています。正確な名前とパラメータ名を知らなくても、この名前付きクエリを動的に呼び出すことができます。抽象JPA DAOで名前付きクエリを抽象化

例として、以下のエンティティを想像し、私は正確に知っている必要はありませんので、AbstractDaofindByName()メソッドを実装する必要がありますどのよう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); 
    } 
} 

名前とパラメータ名?

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"であるため、このパターンに従って名前付きクエリを変更しようとします。このクエリのパラメータも同じ名前にする必要があります。また、定位置パラメータを使用することもできます。あなたのfindメソッドは、あなたがプログラムで「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がそのインタフェースを実装するエンティティのみを受け入れるように指定することができます。これは、クエリパラメータの一貫性のあるネーミングを必要としますが

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

... –

0

明白な方法は

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

またはコンストラクタ引数としてabstract方法を使用して抽象スーパークラスへの具体的なクラスから値を渡すことであろう異なるエンティティに対して。

これらのスニペットのマイナーな改善にも注意してください。

0

にされオン(および可能でしょう他のクエリ)。

これはJavaでは不可能なので、@ NamedQueryはベンダー固有のものとして定義されているクエリヒントをサポートしています。不明なヒントは無視されます。あなたは、一般的なDAOはentityClassから戻って読むことができることを、ここに独自のデータを追加することができます。それは、私は微塵の概念の一種で住みたいコンセプトを「ラップだ

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