Sweet!
I am still tripping over Java 1.5 syntax so it took me a few minutes to
understand the code. And I like it ;-)
Now I'm thinking of a good way to integrate this approach in Cayenne
API. Some sort of strategy parameter on a query... Or maybe keep query
objects simple and instead introduce something similar to your
QueryFactory... I'd call it QueryUtils (just like DataObjectUtils), but
we have an old version of QueryUtils still around, so I am trying to
think of another name...
In the meantime feel free to upload any code that you can share to the
Wiki examples area -
http://objectstyle.org/confluence/display/CAY/Cayenne+Examples If you
get a chance to do that, let me know your id - I'll give you the needed
permissions.
Thanks
Andrus
On Apr 17, 2005, at 7:20 PM, Mikaël Cluseau wrote:
> Andrus,
>
> Here is the method I use to get the same behaviour. I use two queries
> but it is still faster (in fact, .3 seconds for the request on primary
> keys and 1.4 to get the full rows from the PKs, I don't really
> understand why it is that slow -- but it is not done if objects are in
> cache). I think it needs some work to be used in the real Cayenne,
> because I didn't checked the strict equivalency in every case (in
> particular, when the original query already gets customDbAttributes, or
> the attributes I don't copy -- a clone method in query could be
> useful).
>
> Notice that the QueryFactory factory used is home-made. Function names
> are self-describing.
>
> public static <T extends DataObject> List<T> query(DataContext context,
> Class<T> clazz, SelectQuery query, boolean fetchByPk) {
> if (!fetchByPk) {
> // Use the normal method
> return query(context, clazz, query);
> }
> DbEntity entity = context.getEntityResolver().lookupDbEntity(clazz);
>
> // Copy the original query
> SelectQuery query2 = new SelectQuery(clazz);
> query2.setQualifier(query.getQualifier());
> query2.addOrderings(query.getOrderings());
> query2.setFetchLimit(query.getFetchLimit());
>
> // But modify the copy
> query2.setDistinct(true);
>
> List<DbAttribute> attrs = entity.getPrimaryKey();
> if (attrs.size() == 1) {
> query2.addCustomDbAttribute(attrs.get(0).getName());
> } else {
> throw new UnsupportedOperationException(
> "Unable to handle multi-columns (" + attrs.size()
> + ") primary keys");
> }
>
> // Performs the modified query
> List results = context.performQuery(query2);
>
> if (results.isEmpty()) {
> // Avoid useless pain
> return new LinkedList<T>();
> }
>
> List<T> cached = new LinkedList<T>();
> Expression e;
> if (attrs.size() == 1) {
> List<Object> pks = new LinkedList<Object>();
> final String name = attrs.get(0).getName();
> for (Object o : results) {
> Object pk = ((DataRow) o).get(name);
> T cachedObj = clazz.cast(context.getObjectStore().getObject(
> new ObjectId(clazz, name, pk)));
> if (cachedObj == null) {
> pks.add(pk);
> } else {
> cached.add(cachedObj);
> }
> }
> e = QueryFactory.createIn("db:" + attrs.get(0).getName(), pks);
> } else {
> throw new UnsupportedOperationException(
> "Unable to handle multi-columns (" + attrs.size()
> + ") primary keys");
> }
>
> if (e == null) {
> // No expression => nothing to get
> return cached;
> }
>
> // Get full and real objects
> List<T> retval = query(context, clazz, new SelectQuery(clazz, e));
> // Ajout des objets en cache
> if (!cached.isEmpty()) {
> retval.addAll(cached);
> }
> // Sort the results
> List<Ordering> orderings = query.getOrderings();
> if (orderings != null && !orderings.isEmpty()) {
> Collections.sort(retval, new CompositeComparator(orderings));
> }
> return retval;
> }
>
> I did it on my spare time so you are free to use it as you want.
This archive was generated by hypermail 2.0.0 : Sun Apr 17 2005 - 21:25:33 EDT