Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><em>EDIT: Added comments as requested by @ifischer</em></p> <p>I think your main problem is that you lose valuable type information by just passing <code>m.erasure</code> as this returns <code>Class[_]</code> instead of <code>Class[T]</code> what you actually want here. Doing a cast before the rest will save you some nasty stuff.</p> <p>Also the unbound wildcards used in JPA 2.0 are a bit annoying as you need to jump some hoops to get around them.</p> <p>As it does not make much sense to query for no attributes I pulled the first attribute out of the <code>*</code>-parameter. This also means that you do not need to start with <code>conjunction</code>.</p> <p>I shortened some names so that the code fits in the box without line breaks:</p> <pre><code>// import java.util.list as JList, so it does not shadow scala.List import java.util.{List =&gt; JList} abstract class SuperDAO[T &lt;: AnyRef, K](implicit m: Manifest[T]) { @PersistenceContext var em: EntityManager = _ // pretend that we have more type info than we have in the Class object. // it is (almost) safe to cast the erasure to Class[T] here def entityClass = m.erasure.asInstanceOf[Class[T]] lazy val cb: CriteriaBuilder = em.getCriteriaBuilder // Type alias for SingularAttributes accepted for this DAOs entity classes // the metamodel will only ever provide you with Attributes of the form // SingularAttribute&lt;? super X,E&gt;, where X is the entity type (as your // entity class may extend from another) and E is the element type. // We would actually like to use a contravariant definition of the first // type parameter here, but as Java has no notion of that in the definition // side, we have to use an existential type to express the contravariance // similar to the way it would be done in Java. type Field[A] = (SingularAttribute[_ &gt;: T,A],A) // As we need at least one attribute to query for, pull the first argument out // of the varargs. def findByAttributes(attribute: Field[_], attributes: Field[_]*): JList[T] = { val cq = cb.createQuery(entityClass) val root = cq.from(entityClass) // shorthand for creating an equal predicate as we need // that multiple times below def equal(a: Field[_]) = cb.equal(root.get(a._1), a._2) // the Seq of Predicates to query for: def checks = Seq( // if there is only one argument we just query for one equal Predicate if (attributes.isEmpty) equal(attribute) // if there are more, map the varargs to equal-Predicates and prepend // the first Predicate to them. then wrap all of them in an and-Predicate else cb.and(equal(attribute) +: attributes.map(equal) : _*) ) // as we already casted the entityClass we do not need to cast here em.createQuery(cq.where(checks : _*)).getResultList } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload