Linda has written up the new typesafe query API. I previously blogged the reasoning behind this stuff here and here.
An open issue that Linda doesn't mention is query execution. I'm trying to convince the rest of the group that we should carry the typesafety all the way through to the query result set. Here's what I wrote to the group a few weeks ago:
Folks, I figured out a refactoring that gives us a way to do typesafe result sets, avoiding the use of Result. In this new approach, CriteriaQuery and Query would both have a type parameter. You could write code like this, if you have a single selection:CriteriaQuery<Order> q = qb.create(Order.class); Root<Order> order = q.from(Order.class); q.select(order); Query<Order> eq = em.createQuery(q); List<Order> res= eq.getTypedResultList();like this, if you have multiple selections and an object to wrap them in:CriteriaQuery<OrderProduct> q = qb.create(OrderProduct.class); Root<Order> order = q.from(Order.class); Join<Item, Product> product = order.join(Order_.items) .join(Item_.product); q.select( qb.construct(OrderProduct.class, order, product) ); Query<OrderProduct> eq = em.createQuery(q); List<OrderProduct> res= eq.getTypedResultList();Or, if you don't have a nice wrapper class like OrderProduct, you can fall back to use Result:CriteriaQuery<Result> q = qb.create(); Root<Order> order = q.from(Order.class); Join<Item, Product> product = order.join(Order_.items) .join(Item_.product); q.select( qb.result(order, product) ); Query<Result> eq = em.createQuery(q); List<Result> res= eq.getTypedResultList();This change let's people directly get typesafe lists of entities or wrappers, which is something that many people have asked for!
The big point about this API is that I can't write a query which selects Foo and then try to put it in a List<Bar>. It's truly typesafe, end-to-end.
The sticking point with this is that javax.persistence.Query does not currently have the needed type parameter, and there are millions of queries written to the JPA 1.0 APIs which would suddenly spit compiler warnings if we added a type parameter. So we might have to introduce a new interface like TypesafeQuery or something.
Join<Item, Product> product = order.join("items").join("product") isn't type-safe.
Excuse me, I should have read the examples properly before copy/pasting, fixed now. :-)
I don't understand why CriteriaQuery returns a Query, instead of directly the results, which would eliminate the backwards compatibility problems.
Query is used for EJBQL-queries, CriteriaQuery is something very different and queries the datastore using criteria. It sounds a lot like dragging unnecessary implementation concerns in the API.
Well, there's other things you need to do via the Query interface, such as parameter binding...
All projects I've seen so far using the JPA 1.0 API do an immediate cast to the generified version of List, so either they are living with compiler warnings or they are suppressing them on the same line.
This means IMHO that having typesafe return types vould be great, and not at all a problem. Query looks so much more natural than TypeSafeQuery
I don't think people are expecting to be able to replace their 1.0 EntityManager with a brand new 2.0 without having to make some application changes... personally I'd love to make this kind of changes, and the eventually warnings are good to help me find where the code needs improvements.
But Query also needs a type parameter - it's going to be Query<X> if it will return List<X> typesafely.
Hi dear in the original string based system i can include property path such as product.category.name How this can be achieved with type safe api thanks
product.get(Product_.category).get(Category_.name)
It is no doubt better than string. However I can create query or its parts using just strings but I can't create type-safe Criteria without entity manager. Please shade some light on why EM is required.
Gays, it is really difficult to remember three inputs in the form? Why I need to type my name and address every time I post here?
Please introduce s:multilineOutputText. It is really strange to see how CRs disappear from my posts.
Oh boy! I did it. I has always been afraid of. I mistyped . I believe you will excuse me that typo.
BTW The button would come in handy.
Yes you can. It's EntityManagerFactory.createQueryBuilder().create().
To be more specific I mean the ability to use Criteria API on the client not the server side. My understanding of the Specification is that I need persistence unit to properly initialize metamodel to be used in Criteria API. Can I use EntityManagerFactory.createQueryBuilder() without bootstrapping on the client side?
Imagine we display the list of users on the page. We would like to add a checkbox to filter disabled users. We would like to add a edit box to enter filter for name. I'd like to construct a simple Expression on the client side and then pass it with the request to the server side. I'd like to have the only method supporting the query of users for this particular page and use Creteria API for filters. I'd like Eclipse to refactor my Wicket UI code authomatically with changes in the domain model.
Well, just means a jar containing your entity classes and X_ metamodel classes, and EntityManagerFactory is just the runtime representation of that. You are certainly going to need those classes on the client side. You're also certainly going to need jpa.jar, which contains the query APIs, and your persistence provider jar, which implements the interfaces.
And if means reading the entity annotations and creating the metamodel, I don't see how that's a problem, since you need it for error detection when you're creating the query.
So your question is really Well, my interpretation is no, but I guess the spec is silent on the issues, so let me check with Linda to see if she thinks we should be more about that.
Sorry to pick up the discussion 2 months ago, but I just saw the discussion today.
In our development, we have always made JPA type safe even with 1.0 version. Here is what we did :
define a new interface EntityManagerEx, which will implements all EntityManager's methods. But also add methods such as this
The Implementation of EntityManagerEx simply delegate to the instance of EntityManage for all other methods and only implements new methods.
Where QueryEx is defined as the following:
public interface QueryEx<T> extends Query { public enum QueryType {NAMED, NATIVE, JPA } List<T> getResultList(); T getSingleResult(); QueryEx<T> setFirstResult(int i); QueryEx<T> setFlushMode(FlushModeType flushModeType); QueryEx<T> setHint(String s, Object o); QueryEx<T> setMaxResults(int i); QueryEx<T> setParameter(int i, Calendar calendar, TemporalType temporalType); QueryEx<T> setParameter(int i, Date date, TemporalType temporalType); QueryEx<T> setParameter(int i, Object o); QueryEx<T> setParameter(String s, Calendar calendar, TemporalType temporalType); QueryEx<T> setParameter(String s, Date date, TemporalType temporalType); QueryEx<T> setParameter(String s, Object o); QueryEx<T> setColumnParameterInfos(Collection<ColumnParameterInfo> columnParameterInfos); .... skips other methods ... }The results is
we can use QueryEx in consistent manager for all type of queries for JPA 1.0, including direct JDBC calls (for cases JPA doesn't suport).
EntityManageEx mEntityManager = getEntityManger(); QueryEx<Integer> q = mEntityManager.createNativeQuery(GEt_COUNT_SQL, Integer.class) .setParameter("configName", configName); count = q.getSingleResult();OR
QueryEx<Config> q = mEntityManager.createNativeQuery(GET_CONFIG_SQL, Config.class) .setParameter(1, configName); //if (mLog.isTraceEnabled()) q.setLogSql(true); List<Config> configs =q.getResultList();Chester