编辑:重写问题。对我来说更重要的是增加赏金。最后一个提示可以让findbyattributes工作(不需要在子类中重新实现它),这将得到我的观点。
在我的应用程序中,我使用新的JPA2条件查询执行类型安全数据库查询。因此,我有一个特性DAO,它应该对我的应用程序中的所有实体都可用。
所以这就是我使用的当前特征的轮廓看起来(有效的)的方式:
trait DAO[T, K](implicit m: Manifest[T]) {
@PersistenceContext
var em:EntityManager = _
lazy val cb:CriteriaBuilder = em.getCriteriaBuilder
def persist(entity: T)
def update(entity: T)
def remove(entity: T)
def findAll(): ArrayList[T]
// Pair of SingularAttribute and corresponding value
// (used for queries for multiple attributes)
type AttributeValuePair[A] = Pair[SingularAttribute[T, A], A]
// Query for entities where given attribute has given value
def findByAttribute[A](attribute:AttributeValuePair[A]):ArrayList[T]
// Query for entities with multiple attributes (like query by example)
def findByAttributes[A](attributes:AttributeValuePair[_]*):ArrayList[T]
}
在具体的DAO中,我将像这样扩展这个特性,设置类型并实现方法(除去除最重要的方法之外的所有方法):
class UserDAO extends DAO[User, Long] {
override type AttributeValuePair[T] = Pair[SingularAttribute[User, T], T]
override def findByAttributes[T](attributes:AttributeValuePair[_]*):ArrayList[User] = {
val cq = cb.createQuery(classOf[User])
val queryRoot = cq.from(classOf[User])
var criteria = cb.conjunction
for (pair <- attributes)
criteria = cb.and(cb.equal(queryRoot.get(pair._1), pair._2 ))
cq.where(Seq(criteria):_*)
val results = em.createQuery(cq).getResultList
results.asInstanceOf[ArrayList[User]]
}
}
顺便说一句,findbyattributes真的很好用。例子:
val userList = userEJB.findByAttributes(
User_.title -> Title.MR,
User_.email -> "email@test.com"
)
我意识到
findByAttributes
是如此的通用,在我的应用程序实现DAO的所有类中都是一样的。唯一改变的是方法中使用的类型。所以在另一个类中,wich继承了dao,
def findByAttributes[T](attributes:AttributeValuePair[_]*):ArrayList[Message] = {
val cq = cb.createQuery(classOf[Message])
val queryRoot = cq.from(classOf[Message])
var criteria = cb.conjunction
for (pair <- attributes)
criteria = cb.and(cb.equal(queryRoot.get(pair._1), pair._2 ))
cq.where(Seq(criteria):_*)
val results = em.createQuery(cq).getResultList
results.asInstanceOf[ArrayList[User]]
}
所以我创建了一个新的抽象类superdao,它应该包含实现的泛型方法,这样我就不必在每个子类中重新实现它们。
在Landei的帮助下(谢谢),我的超级道当前的(最重要的部分)实现如下
abstract class SuperDAO[T, K](implicit m: Manifest[T]) {
@PersistenceContext
var em:EntityManager = _
lazy val cb:CriteriaBuilder = em.getCriteriaBuilder
type AttributeValuePair[A] = Pair[SingularAttribute[T, A], A]
def findByAttributes(attributes:AttributeValuePair[_]*):ArrayList[T] = {
val cq = cb.createQuery(m.erasure)
val queryRoot = cq.from(m.erasure)
var criteria = cb.conjunction
for (pair <- attributes) {
criteria = cb.and(
cb.equal(
// gives compiler error
queryRoot.get[SingularAttribute[T,_]](pair._1)
)
,pair._2
)
}
cq.where(Seq(criteria):_*)
val results = em.createQuery(cq).getResultList
results.asInstanceOf[ArrayList[T]]
}
因此,当前的问题是queryroot.get的行产生以下错误:
overloaded method value get with alternatives:
(java.lang.String)javax.persistence.criteria.Path
[javax.persistence.metamodel.SingularAttribute[T, _]] <and>
(javax.persistence.metamodel.SingularAttribute[_ >: Any,
javax.persistence.metamodel.SingularAttribute[T,_]])
javax.persistence.criteria.Path
[javax.persistence.metamodel.SingularAttribute[T, _]]
cannot be applied to
(javax.persistence.metamodel.SingularAttribute[T,_$1])
1美元是什么意思????
如果需要的话:
SingularAttribute Javadoc
编辑@ Landei:
将方法签名更改为
def findByAttributesOld[A](attributes:AttributeValuePair[A]*):ArrayList[T] = {
和queryroot.get
queryRoot.get[A](pair._1.asInstanceOf[SingularAttribute[T,A]])
结果是(更短!)错误:
overloaded method value get with alternatives:
(java.lang.String)javax.persistence.criteria.Path[A] <and>
(javax.persistence.metamodel.SingularAttribute[_ >: Any, A])
javax.persistence.criteria.Path[A] cannot be applied to
(javax.persistence.metamodel.SingularAttribute[T,A])
解决方案
@三多村口
似乎起作用了。必须测试一下。不过,如果可能的话,我也希望有一个更短的解决方案!