java - 在抽象的JPA DAO中,抽象命名查询

  显示原文与译文双语对照的内容
0 0

我有一个抽象的DAO类,它使用参数化类型 E ( 实体) 和 K ( 主键) 。 在每个实体中我都有一个 @NamedQuery 。 我想动态调用这个命名查询,而不知道它的确切名称和参数名。

作为一个例子,假设下面的实体 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);
 } 
}

如何在 AbstractDao 中实现 findByName() 方法,以便不需要知道确切的名称和参数名?


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

//...
}

时间: 原作者:

0 0

命名查询的命名约定通常为 <Entity Name>.findBy<PropertyAndAnotherProperty> ,"城市。findByName"在你的例子中,我将试图改变这个 Pattern 命名查询跟踪。 这个查询的参数也应该具有相同的名称,或者你可以使用位置参数。 然后你的查找方法将变成


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

原作者:
0 0

最简单的方法是将查询的NAME 传递给抽象DAO的构造函数:


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

然后在City中定义一个 public static final 字符串以保存名称:


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

或者你可以将DaoAbstreact声明为抽象,然后在其中使用这样的方法:


public abstract String getFindByNameQueryName();

在ConcreteCityDao中实现。

finally 你也可以引入枚举:


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可以从传入的类中确定类型。 为了确保 NOT 忘记将实体添加到枚举中,可以让每个实体实现一个带有 getNamedEntityType() 方法的接口。 然后你可以指定抽象泛型DAO只接受实现该接口的实体。

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

尽管这需要对不同实体的查询参数命名一致。

还注意到这些Fragment的细微改进。

原作者:
0 0

你基本上希望的是注释定义命名查询的注释,这样,你可以编程方式发现"findByName"查询是( 和可能的其他查询) 查询。

因为这在Java中是不可能的,所以你可以使用 @NamedQuery 支持查询提示,即定义为特定于供应商的。 忽略未知提示。你可以在这里添加自己的数据,泛型DAO可以从 entityClass 中读取这些数据:


@NamedQuery(
 name="findCityByname",
 query="FROM CITY c WHERE name = :CityName",
 hints=@QueryHint(name="genericDAO.type", value="findByName")
)

原作者:
...