Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/objectstyle/cayenne/access/util/PrefetchHelper.java


1   /* ====================================================================
2    *
3    * The ObjectStyle Group Software License, Version 1.0
4    *
5    * Copyright (c) 2002-2003 The ObjectStyle Group
6    * and individual authors of the software.  All rights reserved.
7    *
8    * Redistribution and use in source and binary forms, with or without
9    * modification, are permitted provided that the following conditions
10   * are met:
11   *
12   * 1. Redistributions of source code must retain the above copyright
13   *    notice, this list of conditions and the following disclaimer.
14   *
15   * 2. Redistributions in binary form must reproduce the above copyright
16   *    notice, this list of conditions and the following disclaimer in
17   *    the documentation and/or other materials provided with the
18   *    distribution.
19   *
20   * 3. The end-user documentation included with the redistribution, if
21   *    any, must include the following acknowlegement:
22   *       "This product includes software developed by the
23   *        ObjectStyle Group (http://objectstyle.org/)."
24   *    Alternately, this acknowlegement may appear in the software itself,
25   *    if and wherever such third-party acknowlegements normally appear.
26   *
27   * 4. The names "ObjectStyle Group" and "Cayenne"
28   *    must not be used to endorse or promote products derived
29   *    from this software without prior written permission. For written
30   *    permission, please contact andrus@objectstyle.org.
31   *
32   * 5. Products derived from this software may not be called "ObjectStyle"
33   *    nor may "ObjectStyle" appear in their names without prior written
34   *    permission of the ObjectStyle Group.
35   *
36   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39   * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
40   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47   * SUCH DAMAGE.
48   * ====================================================================
49   *
50   * This software consists of voluntary contributions made by many
51   * individuals on behalf of the ObjectStyle Group.  For more
52   * information on the ObjectStyle Group, please see
53   * <http://objectstyle.org/>.
54   */
55  package org.objectstyle.cayenne.access.util;
56  
57  import java.util.ArrayList;
58  import java.util.HashMap;
59  import java.util.List;
60  import java.util.ListIterator;
61  import java.util.Map;
62  
63  import org.objectstyle.cayenne.CayenneRuntimeException;
64  import org.objectstyle.cayenne.DataObject;
65  import org.objectstyle.cayenne.ObjectId;
66  import org.objectstyle.cayenne.access.DataContext;
67  import org.objectstyle.cayenne.access.ToManyList;
68  import org.objectstyle.cayenne.exp.Expression;
69  import org.objectstyle.cayenne.exp.ExpressionFactory;
70  import org.objectstyle.cayenne.map.DbRelationship;
71  import org.objectstyle.cayenne.map.ObjEntity;
72  import org.objectstyle.cayenne.map.ObjRelationship;
73  import org.objectstyle.cayenne.query.SelectQuery;
74  
75  /**
76   * @author Arndt Brenschede
77   */
78  public class PrefetchHelper {
79  
80      /**
81       * Resolves a toOne relationship for a list of objects.
82       * (performance tuning only)
83       */
84      public static void resolveToOneRelations(
85          DataContext context,
86          List objects,
87          String relName) {
88          int nobjects = objects.size();
89          if (nobjects == 0)
90              return;
91  
92          List oids = new ArrayList(nobjects);
93  
94          for (int i = 0; i < nobjects; i++) {
95              DataObject sourceObject = (DataObject) objects.get(i);
96              DataObject targetObject =
97                  (DataObject) sourceObject.readPropertyDirectly(relName);
98              
99              ObjectId oid = targetObject.getObjectId();
100             oids.add(oid);
101         }
102         // this maybe suboptimal, cause it uses an OR .. OR .. OR .. expression
103         // instead of IN (..) - to be compatble with compound keys - 
104         // however, it seems to be quite fast as well
105         SelectQuery sel = QueryUtils.selectQueryForIds(oids);
106         context.performQuery(sel);
107     }
108 
109     /**
110      * Resolves a toMany relation for a list of objects.
111      * (performance tuning only)
112      * 
113      * <p>WARNING: this is a bit of a hack - it works for my
114      * toMany's, but it possibly doesn't work in all cases.</p>
115      * 
116      * 
117      * <p>*** It definitly does not work for compound keys ***</p>
118      */
119     public static void resolveToManyRelations(
120         DataContext context,
121         List objects,
122         String relName) {
123 
124         int nobjects = objects.size();
125         if (nobjects == 0)
126             return;
127 
128         String dbKey = null;
129         Map listMap = new HashMap(nobjects);
130 
131         // put the object-ids in a map for later assignment of the
132         // query results
133 
134         for (int i = 0; i < nobjects; i++) {
135             DataObject object = (DataObject) objects.get(i);
136             ObjectId oid = object.getObjectId();
137             if (dbKey == null) {
138                 Map id = oid.getIdSnapshot();
139                 if (id.size() != 1) {
140                     throw new CayenneRuntimeException("resolveToManyRelations expects single keys for now...");
141                 }
142                 dbKey = (String) id.keySet().iterator().next();
143             }
144             listMap.put(oid.getValueForAttribute(dbKey), new ArrayList());
145         }
146 
147         ObjEntity ent =
148             context.getEntityResolver().lookupObjEntity(
149                 (DataObject) objects.get(0));
150         ObjRelationship rel = (ObjRelationship) ent.getRelationship(relName);
151         ObjEntity destEnt = (ObjEntity) rel.getTargetEntity();
152 
153         List dbRels = rel.getDbRelationships();
154 
155         // sanity check
156         if (dbRels == null || dbRels.size() == 0) {
157             throw new CayenneRuntimeException(
158                 "ObjRelationship '" + rel.getName() + "' is unmapped.");
159         }
160 
161         // build a reverse DB path
162         // ...while reverse ObjRelationship may be absent,
163         // reverse DB must always be there...
164         StringBuffer buf = new StringBuffer();
165         ListIterator it = dbRels.listIterator(dbRels.size());
166         while (it.hasPrevious()) {
167             if (buf.length() > 0) {
168                 buf.append(".");
169             }
170             DbRelationship dbRel = (DbRelationship) it.previous();
171             DbRelationship reverse = dbRel.getReverseRelationship();
172 
173             // another sanity check
174             if (reverse == null) {
175                 throw new CayenneRuntimeException(
176                     "DbRelatitionship '"
177                         + dbRel.getName()
178                         + "' has no reverse relationship");
179             }
180 
181             buf.append(reverse.getName());
182         }
183 
184         // do the query
185         SelectQuery sel =
186             new SelectQuery(
187                 destEnt,
188                 ExpressionFactory.binaryDbPathExp(
189                     Expression.IN,
190                     buf.toString(),
191                     ExpressionFactory.unaryExp(Expression.LIST, objects)));
192         sel.setFetchingDataRows(true);
193         List results = context.performQuery(sel);
194 
195         // sort the resulting objects into individual lists for each source object
196         int nrows = results.size();
197         for (int k = 0; k < nrows; k++) {
198             Map row = (Map) results.get(k);
199             ((List) listMap.get(row.get(dbKey))).add(
200                 context.objectFromDataRow(destEnt, row, false));
201         }
202 
203         // and finally set these lists in the relation targets
204         for (int i = 0; i < nobjects; i++) {
205             DataObject object = (DataObject) objects.get(i);
206             ObjectId oid = object.getObjectId();
207             List list = (List) listMap.get(oid.getValueForAttribute(dbKey));
208 
209             ((ToManyList) object.readPropertyDirectly(relName)).setObjectList(
210                 list);
211         }
212     }
213 }