Переместите реализацию общего метода для абстрактного суперкласса

Править: Переписал вопрос. Добавленная щедрость как его важное для меня. Заключительная подсказка, с которой я могу заставить 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, кажется, работает. Должны протестировать его немного. Но я также ценил бы более короткое решение, если его возможное вообще!

6
задан Ingo Fischer 28 July 2010 в 10:10
поделиться