Править: Переписал вопрос. Добавленная щедрость как его важное для меня. Заключительная подсказка, с которой я могу заставить findByAttributes работать (не повторно реализовывая его в подклассах) поймет мои мысли.
В моем приложении я делаю безопасные с точки зрения типов запросы базы данных с новым Запросом Критериев JPA2. Поэтому у меня есть ДАО черты, который должен быть (ре), применимое для ВСЕХ объектов в моем приложении. Таким образом, это - то, как схема, на которую похожа текущая черта, которая я использую (который работает):
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]
}
В конкретном ДАО я расширяю эту черту как это, устанавливая тип и реализовывая методы (удалил все кроме самого важного метода):
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]]
}
}
BTW, findByAttributes действительно хорош использовать. Пример:
val userList = userEJB.findByAttributes(
User_.title -> Title.MR,
User_.email -> "email@test.com"
)
Я понял, это findByAttributes
так универсально, что это - то же во ВСЕХ классах моего приложения, которые реализуют ДАО. Единственная вещь, которая изменениями является Тип, используемый в методе. Таким образом в другом классе, который наследовал ДАО,
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 (спасибо) (самая важная часть моего) текущая реализация моего SuperDAO похожа на это
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, _]]
(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]
(javax.persistence.metamodel.SingularAttribute[_ >: Any, A])
javax.persistence.criteria.Path[A] cannot be applied to
(javax.persistence.metamodel.SingularAttribute[T,A])
Решение @Sandor Murakozi, кажется, работает. Должны протестировать его немного. Но я также ценил бы более короткое решение, если его возможное вообще!