You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2010/05/31 03:34:27 UTC

svn commit: r949641 - in /cayenne/main/trunk: docs/doc/src/main/resources/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/ framework/cayenn...

Author: aadamchik
Date: Mon May 31 01:34:26 2010
New Revision: 949641

URL: http://svn.apache.org/viewvc?rev=949641&view=rev
Log:
CAY-1438 refactoring EntityInheritanceTree lookups

* EntityResolver now returns non-null EIT instance for all existing entities
* Added ClassDescriptor.hasSubclasses() method to avoid non-obvious EIT checks throughout the code

Modified:
    cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/JoinedIdParentAttachementStrategy.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectResolver.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DataRowPostProcessor.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssembler.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ObjRelationship.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SelectQueryPrefetchRouterAction.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/ClassDescriptor.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LazyClassDescriptorDecorator.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptor.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorFactory.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/map/EntityResolverInheritanceTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/reflect/MockClassDescriptor.java
    cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/ObjGraphBuilder.java

Modified: cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt (original)
+++ cayenne/main/trunk/docs/doc/src/main/resources/RELEASE-NOTES.txt Mon May 31 01:34:26 2010
@@ -41,6 +41,7 @@ CAY-1422 Convert EventManager to an inte
 CAY-1424 DI: support for named service injection and flexible map/list binding
 CAY-1425 Remove Configuration sharedConfiguration singleton affecting DataContext deserialization, CayenneDataObject XML deserialization, DataContext static factory method. 
 CAY-1433 Change #chunk behaviour to skipe only null arguments (don't skip 0 or false)
+CAY-1438 refactoring EntityInheritanceTree lookups
 
 Bug Fixes Since 3.0:
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/JoinedIdParentAttachementStrategy.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/JoinedIdParentAttachementStrategy.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/JoinedIdParentAttachementStrategy.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/JoinedIdParentAttachementStrategy.java Mon May 31 01:34:26 2010
@@ -19,12 +19,10 @@
 package org.apache.cayenne.access;
 
 import java.util.Collection;
-import java.util.Collections;
 
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.graph.GraphManager;
 import org.apache.cayenne.map.ObjEntity;
@@ -54,12 +52,7 @@ class JoinedIdParentAttachementStrategy 
                 .getReverseDbRelationshipPath()
                 + ".";
 
-        if (parentDescriptor.getEntityInheritanceTree() == null) {
-            sourceEntities = Collections.singletonList(parentDescriptor.getEntity());
-        }
-        else {
-            sourceEntities = parentDescriptor.getEntityInheritanceTree().allSubEntities();
-        }
+        sourceEntities = parentDescriptor.getEntityInheritanceTree().allSubEntities();
 
         this.node = node;
         this.graphManager = graphManager;

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectResolver.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectResolver.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectResolver.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/ObjectResolver.java Mon May 31 01:34:26 2010
@@ -34,7 +34,6 @@ import org.apache.cayenne.PersistenceSta
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.EntityInheritanceTree;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.reflect.ClassDescriptor;
@@ -83,10 +82,7 @@ class ObjectResolver {
         this.refreshObjects = refresh;
         this.descriptor = descriptor;
 
-        EntityInheritanceTree inheritanceTree = context
-                .getEntityResolver()
-                .lookupInheritanceTree(descriptor.getEntity());
-        this.descriptorResolutionStrategy = inheritanceTree != null
+        this.descriptorResolutionStrategy = descriptor.hasSubclasses()
                 ? new InheritanceStrategy()
                 : new NoInheritanceStrategy();
     }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java Mon May 31 01:34:26 2010
@@ -37,7 +37,6 @@ import org.apache.cayenne.exp.parser.AST
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbJoin;
 import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.EntityInheritanceTree;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.query.PrefetchTreeNode;
@@ -142,26 +141,12 @@ class PrefetchProcessorJointNode extends
         // since JDBC row reader won't inject JOINED entity name, we have to
         // detect it here...
 
-        ObjEntity entity = null;
         ClassDescriptor descriptor = resolver.getDescriptor();
-        EntityInheritanceTree entityInheritanceTree = descriptor
-                .getEntityInheritanceTree();
-
-        if (entityInheritanceTree != null) {
-            entity = entityInheritanceTree.entityMatchingRow(row);
-        }
-
-        if (entity == null) {
-            entity = descriptor.getEntity();
-        }
-
+        ObjEntity entity = descriptor.getEntityInheritanceTree().entityMatchingRow(row);
         row.setEntityName(entity.getName());
         return row;
     }
 
-    // ***** private methods *****
-    // ========================================================
-
     /**
      * Configures row columns mapping for this node entity.
      */

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DataRowPostProcessor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DataRowPostProcessor.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DataRowPostProcessor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/DataRowPostProcessor.java Mon May 31 01:34:26 2010
@@ -34,6 +34,7 @@ import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.EntityInheritanceTree;
 import org.apache.cayenne.map.ObjAttribute;
 import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.reflect.ClassDescriptor;
 
 /**
  * Deals with DataRow type conversion in inheritance situations.
@@ -55,7 +56,8 @@ class DataRowPostProcessor {
 
         ColumnDescriptor[] columns = translator.getResultColumns();
 
-        Map<String, Collection<ColumnOverride>> columnOverrides = new HashMap<String, Collection<ColumnOverride>>(2);
+        Map<String, Collection<ColumnOverride>> columnOverrides = new HashMap<String, Collection<ColumnOverride>>(
+                2);
 
         Iterator it = attributeOverrides.entrySet().iterator();
         while (it.hasNext()) {
@@ -102,15 +104,22 @@ class DataRowPostProcessor {
         }
 
         // inject null post-processor
-        return columnOverrides.isEmpty() ? null : new DataRowPostProcessor(translator
-                .getRootInheritanceTree(), columnOverrides);
+        if (columnOverrides.isEmpty()) {
+            return null;
+        }
+
+        ClassDescriptor rootDescriptor = translator
+                .getQueryMetadata()
+                .getClassDescriptor();
+
+        return new DataRowPostProcessor(rootDescriptor, columnOverrides);
     }
 
-    private DataRowPostProcessor(EntityInheritanceTree inheritanceTree,
+    private DataRowPostProcessor(ClassDescriptor classDescriptor,
             Map<String, Collection<ColumnOverride>> columnOverrides) {
 
-        if (inheritanceTree != null && inheritanceTree.getChildren().size() > 0) {
-            this.inheritanceTree = inheritanceTree;
+        if (classDescriptor != null && classDescriptor.hasSubclasses()) {
+            this.inheritanceTree = classDescriptor.getEntityInheritanceTree();
             this.columnOverrides = columnOverrides;
         }
         else {
@@ -145,9 +154,7 @@ class DataRowPostProcessor {
         }
         else {
             ObjEntity entity = inheritanceTree.entityMatchingRow(row);
-            return entity != null
-                    ? columnOverrides.get(entity.getName())
-                    : null;
+            return entity != null ? columnOverrides.get(entity.getName()) : null;
         }
     }
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/jdbc/JDBCResultIterator.java Mon May 31 01:34:26 2010
@@ -140,7 +140,7 @@ public class JDBCResultIterator implemen
             return new IdRowReader(descriptor, queryMetadata);
         }
         else if (resultMetadata.getClassDescriptor() != null
-                && resultMetadata.getClassDescriptor().getEntityInheritanceTree() != null) {
+                && resultMetadata.getClassDescriptor().hasSubclasses()) {
             return new InheritanceAwareEntityRowReader(descriptor, resultMetadata);
         }
         else {
@@ -156,7 +156,7 @@ public class JDBCResultIterator implemen
             return new IdRowReader(descriptor, queryMetadata);
         }
         else if (queryMetadata.getClassDescriptor() != null
-                && queryMetadata.getClassDescriptor().getEntityInheritanceTree() != null) {
+                && queryMetadata.getClassDescriptor().hasSubclasses()) {
             return new InheritanceAwareRowReader(descriptor, queryMetadata);
         }
         else {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QualifierTranslator.java Mon May 31 01:34:26 2010
@@ -34,11 +34,11 @@ import org.apache.cayenne.exp.parser.Pat
 import org.apache.cayenne.exp.parser.SimpleNode;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.EntityInheritanceTree;
 import org.apache.cayenne.map.JoinType;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.query.QualifiedQuery;
 import org.apache.cayenne.query.Query;
+import org.apache.cayenne.reflect.ClassDescriptor;
 import org.apache.commons.collections.IteratorUtils;
 import org.apache.commons.collections.Transformer;
 
@@ -86,11 +86,13 @@ public class QualifierTranslator extends
         ObjEntity entity = getObjEntity();
 
         if (entity != null) {
-            EntityInheritanceTree tree = queryAssembler
+
+            ClassDescriptor descriptor = queryAssembler
                     .getEntityResolver()
-                    .lookupInheritanceTree(entity);
-            Expression entityQualifier = (tree != null) ? tree
-                    .qualifierForEntityAndSubclasses() : entity.getDeclaredQualifier();
+                    .getClassDescriptor(entity.getName());
+            Expression entityQualifier = descriptor
+                    .getEntityInheritanceTree()
+                    .qualifierForEntityAndSubclasses();
             if (entityQualifier != null) {
                 qualifier = (qualifier != null)
                         ? qualifier.andExp(entityQualifier)

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssembler.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssembler.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssembler.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/access/trans/QueryAssembler.java Mon May 31 01:34:26 2010
@@ -30,7 +30,6 @@ import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.map.DbAttribute;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.EntityInheritanceTree;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.JoinType;
 import org.apache.cayenne.map.ObjEntity;
@@ -57,7 +56,7 @@ public abstract class QueryAssembler {
      * PreparedStatement attributes matching entries in <code>values</code> list.
      */
     protected List<DbAttribute> attributes = new ArrayList<DbAttribute>();
-    
+
     /**
      * The index parameter will be inserted at in parameter list
      */
@@ -81,15 +80,6 @@ public abstract class QueryAssembler {
     }
 
     /**
-     * Returns an EntityInheritanceTree for the root entity.
-     * 
-     * @since 1.1
-     */
-    public EntityInheritanceTree getRootInheritanceTree() {
-        return getEntityResolver().lookupInheritanceTree(getRootEntity());
-    }
-
-    /**
      * Returns query object being processed.
      */
     public Query getQuery() {
@@ -223,7 +213,7 @@ public abstract class QueryAssembler {
                 }
             }
         }
-        
+
         if (queryMetadata.getStatementFetchSize() != 0) {
             stmt.setFetchSize(queryMetadata.getStatementFetchSize());
         }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityInheritanceTree.java Mon May 31 01:34:26 2010
@@ -135,6 +135,9 @@ public class EntityInheritanceTree {
     }
 
     /**
+     * Returns a collection containing this inheritance tree node entity and all its
+     * subentities.
+     * 
      * @since 3.0
      */
     public Collection<ObjEntity> allSubEntities() {

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/EntityResolver.java Mon May 31 01:34:26 2010
@@ -565,7 +565,7 @@ public class EntityResolver implements M
             for (Procedure proc : map.getProcedures()) {
                 procedureCache.put(proc.getName(), proc);
             }
-            
+
             // index embeddables
             embeddableCache.putAll(map.getEmbeddableMap());
 
@@ -587,8 +587,7 @@ public class EntityResolver implements M
             // index ObjEntity inheritance
             for (ObjEntity oe : map.getObjEntities()) {
 
-                // build inheritance tree... include nodes that
-                // have no children to avoid unneeded cache rebuilding on lookup...
+                // build inheritance tree
                 EntityInheritanceTree node = entityInheritanceCache.get(oe.getName());
                 if (node == null) {
                     node = new EntityInheritanceTree(oe);
@@ -654,8 +653,9 @@ public class EntityResolver implements M
 
     /**
      * Returns EntityInheritanceTree representing inheritance hierarchy that starts with a
-     * given ObjEntity as root, and includes all its subentities. If ObjEntity has no
-     * known subentities, null is returned.
+     * given ObjEntity as root, and includes all its subentities.
+     * 
+     * @deprecated since 3.1 use {@link #lookupInheritanceTree(String)}.
      */
     public EntityInheritanceTree lookupInheritanceTree(ObjEntity entity) {
         return lookupInheritanceTree(entity.getName());
@@ -663,8 +663,8 @@ public class EntityResolver implements M
 
     /**
      * Returns EntityInheritanceTree representing inheritance hierarchy that starts with a
-     * given ObjEntity as root, and includes all its subentities. If ObjEntity has no
-     * known subentities, null is returned.
+     * given ObjEntity as root, and includes all its subentities. Returns non-null object
+     * for all existing entities, even those that don't have super or subclasses.
      * 
      * @since 3.0
      */
@@ -682,8 +682,7 @@ public class EntityResolver implements M
             tree = entityInheritanceCache.get(entityName);
         }
 
-        // don't return "trivial" trees
-        return (tree == null || tree.getChildrenCount() == 0) ? null : tree;
+        return tree;
     }
 
     /**

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ObjRelationship.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ObjRelationship.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ObjRelationship.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/map/ObjRelationship.java Mon May 31 01:34:26 2010
@@ -192,11 +192,11 @@ public class ObjRelationship extends Rel
         if (target == null) {
             return null;
         }
-        
+
         Entity source = getSourceEntity();
 
         for (ObjRelationship relationship : target.getRelationships()) {
- 
+
             if (relationship.getTargetEntity() != source) {
                 continue;
             }
@@ -338,8 +338,15 @@ public class ObjRelationship extends Rel
      * @since 3.0
      */
     public boolean isSourceDefiningTargetPrecenseAndType(EntityResolver entityResolver) {
-        return !isOptional()
-                && entityResolver.lookupInheritanceTree(getTargetEntityName()) == null;
+
+        if (isOptional()) {
+            return false;
+        }
+
+        EntityInheritanceTree inheritanceTree = entityResolver
+                .lookupInheritanceTree(getTargetEntityName());
+
+        return inheritanceTree == null || inheritanceTree.getChildren().isEmpty();
     }
 
     /**

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SelectQueryPrefetchRouterAction.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SelectQueryPrefetchRouterAction.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SelectQueryPrefetchRouterAction.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/query/SelectQueryPrefetchRouterAction.java Mon May 31 01:34:26 2010
@@ -23,10 +23,9 @@ import java.util.Iterator;
 
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.map.EntityInheritanceTree;
 import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.reflect.ClassDescriptor;
 import org.apache.cayenne.util.CayenneMapEntry;
 
 /**
@@ -39,8 +38,7 @@ class SelectQueryPrefetchRouterAction im
     SelectQuery query;
     QueryRouter router;
     EntityResolver resolver;
-    ObjEntity entity;
-    EntityInheritanceTree inheritanceTree;
+    ClassDescriptor classDescriptor;
 
     /**
      * Routes query prefetches, but not the query itself.
@@ -51,8 +49,7 @@ class SelectQueryPrefetchRouterAction im
             this.query = query;
             this.router = router;
             this.resolver = resolver;
-            this.entity = query.getMetaData(resolver).getObjEntity();
-            this.inheritanceTree = resolver.lookupInheritanceTree(entity);
+            this.classDescriptor = query.getMetaData(resolver).getClassDescriptor();
 
             query.getPrefetchTree().traverse(this);
         }
@@ -71,7 +68,8 @@ class SelectQueryPrefetchRouterAction im
         String prefetchPath = node.getPath();
 
         // find last relationship
-        Iterator<CayenneMapEntry> it = entity.resolvePathComponents(prefetchPath);
+        Iterator<CayenneMapEntry> it = classDescriptor.getEntity().resolvePathComponents(
+                prefetchPath);
 
         ObjRelationship relationship = null;
         while (it.hasNext()) {
@@ -79,17 +77,18 @@ class SelectQueryPrefetchRouterAction im
         }
 
         if (relationship == null) {
-            throw new CayenneRuntimeException("Invalid prefetch '"
-                    + prefetchPath
-                    + "' for entity: "
-                    + entity.getName());
+            throw new CayenneRuntimeException(
+                    "Invalid prefetch '%s' for entity '%s'",
+                    prefetchPath,
+                    classDescriptor.getEntity().getName());
         }
 
         // chain query and entity qualifiers
         Expression queryQualifier = query.getQualifier();
 
-        Expression entityQualifier = (inheritanceTree != null) ? inheritanceTree
-                .qualifierForEntityAndSubclasses() : entity.getDeclaredQualifier();
+        Expression entityQualifier = classDescriptor
+                .getEntityInheritanceTree()
+                .qualifierForEntityAndSubclasses();
 
         if (entityQualifier != null) {
             queryQualifier = (queryQualifier != null) ? queryQualifier
@@ -102,7 +101,7 @@ class SelectQueryPrefetchRouterAction im
                 prefetchPath,
                 relationship);
 
-        prefetchQuery.setQualifier(entity.translateToRelatedEntity(
+        prefetchQuery.setQualifier(classDescriptor.getEntity().translateToRelatedEntity(
                 queryQualifier,
                 prefetchPath));
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/ClassDescriptor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/ClassDescriptor.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/ClassDescriptor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/ClassDescriptor.java Mon May 31 01:34:26 2010
@@ -58,6 +58,13 @@ public interface ClassDescriptor {
     EntityInheritanceTree getEntityInheritanceTree();
 
     /**
+     * Returns whether this class has persistent subclasses.
+     * 
+     * @since 3.1
+     */
+    boolean hasSubclasses();
+
+    /**
      * Returns a class mapped by this descriptor.
      */
     Class<?> getObjectClass();

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LazyClassDescriptorDecorator.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LazyClassDescriptorDecorator.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LazyClassDescriptorDecorator.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/LazyClassDescriptorDecorator.java Mon May 31 01:34:26 2010
@@ -93,6 +93,11 @@ public class LazyClassDescriptorDecorato
         checkDescriptorInitialized();
         return descriptor.getEntityInheritanceTree();
     }
+    
+    public boolean hasSubclasses() {
+        checkDescriptorInitialized();
+        return descriptor.hasSubclasses();
+    }
 
     public Class<?> getObjectClass() {
 

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptor.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptor.java Mon May 31 01:34:26 2010
@@ -415,4 +415,9 @@ public class PersistentDescriptor implem
     public void setEntityInheritanceTree(EntityInheritanceTree entityInheritanceTree) {
         this.entityInheritanceTree = entityInheritanceTree;
     }
+
+    public boolean hasSubclasses() {
+        return entityInheritanceTree != null
+                && !entityInheritanceTree.getChildren().isEmpty();
+    }
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorFactory.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorFactory.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorFactory.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/reflect/PersistentDescriptorFactory.java Mon May 31 01:34:26 2010
@@ -123,7 +123,7 @@ public abstract class PersistentDescript
 
         EntityInheritanceTree inheritanceTree = descriptorMap
                 .getResolver()
-                .lookupInheritanceTree(descriptor.getEntity());
+                .lookupInheritanceTree(descriptor.getEntity().getName());
         descriptor.setEntityInheritanceTree(inheritanceTree);
         indexSubclassDescriptors(descriptor, inheritanceTree);
         indexQualifiers(descriptor, inheritanceTree);

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/map/EntityResolverInheritanceTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/map/EntityResolverInheritanceTest.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/map/EntityResolverInheritanceTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/map/EntityResolverInheritanceTest.java Mon May 31 01:34:26 2010
@@ -24,44 +24,33 @@ import org.apache.cayenne.unit.PeopleCas
 /**
  */
 public class EntityResolverInheritanceTest extends PeopleCase {
+
     protected EntityResolver resolver;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-
         resolver = new EntityResolver(getDomain().getDataMaps());
     }
 
-    private ObjEntity getAbstractPerson() {
-        return getObjEntity("AbstractPerson");
-    }
-
-    private ObjEntity getEmployee() {
-        return getObjEntity("Employee");
-    }
-
-    private ObjEntity getManager() {
-        return getObjEntity("Manager");
-    }
-
     public void testLookupAbstractPersonTree() throws Exception {
-        EntityInheritanceTree tree = resolver.lookupInheritanceTree(getAbstractPerson());
+        EntityInheritanceTree tree = resolver.lookupInheritanceTree("AbstractPerson");
         assertNotNull(tree);
         assertEquals(2, tree.getChildrenCount());
-        assertSame(getAbstractPerson(), tree.getEntity());
+        assertSame(getObjEntity("AbstractPerson"), tree.getEntity());
     }
 
     public void testLookupEmployeeTree() throws Exception {
-        EntityInheritanceTree tree = resolver.lookupInheritanceTree(getEmployee());
+        EntityInheritanceTree tree = resolver.lookupInheritanceTree("Employee");
         assertNotNull(tree);
         assertEquals(1, tree.getChildrenCount());
-        assertSame(getEmployee(), tree.getEntity());
+        assertSame(getObjEntity("Employee"), tree.getEntity());
     }
 
     public void testLookupManagerTree() throws Exception {
-        EntityInheritanceTree tree = resolver.lookupInheritanceTree(getManager());
-        assertNull(tree);
+        EntityInheritanceTree tree = resolver.lookupInheritanceTree("Manager");
+        assertNotNull(tree);
+        assertEquals(0, tree.getChildrenCount());
     }
 
     public void testLookupTreeRefresh() throws Exception {
@@ -82,10 +71,10 @@ public class EntityResolverInheritanceTe
         map.addObjEntity(sub1);
         map.addObjEntity(sub2);
 
-        assertNull(resolver.lookupInheritanceTree(super1));
+        assertNull(resolver.lookupInheritanceTree("super1"));
 
         resolver.addDataMap(map);
-        EntityInheritanceTree tree = resolver.lookupInheritanceTree(super1);
+        EntityInheritanceTree tree = resolver.lookupInheritanceTree("super1");
         assertNotNull(tree);
         assertEquals(2, tree.getChildrenCount());
         assertSame(super1, tree.getEntity());

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/reflect/MockClassDescriptor.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/reflect/MockClassDescriptor.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/reflect/MockClassDescriptor.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/reflect/MockClassDescriptor.java Mon May 31 01:34:26 2010
@@ -111,6 +111,10 @@ public class MockClassDescriptor impleme
     public boolean visitProperties(PropertyVisitor visitor) {
         return true;
     }
+    
+    public boolean hasSubclasses() {
+        return false;
+    }
 
     public boolean visitAllProperties(PropertyVisitor visitor) {
         return true;

Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/ObjGraphBuilder.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/ObjGraphBuilder.java?rev=949641&r1=949640&r2=949641&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/ObjGraphBuilder.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/graph/ObjGraphBuilder.java Mon May 31 01:34:26 2010
@@ -26,6 +26,7 @@ import java.util.Map;
 import org.apache.cayenne.configuration.DataChannelDescriptor;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.EntityInheritanceTree;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.event.AttributeEvent;
@@ -60,10 +61,24 @@ class ObjGraphBuilder extends BaseGraphB
 
     @Override
     protected boolean isIsolated(DataChannelDescriptor domain, Entity entity) {
-        EntityResolver entRes = new EntityResolver(((DataChannelDescriptor)mediator.getProject().getRootNode()).getDataMaps());
-        return super.isIsolated(domain, entity)
-                && ((ObjEntity) entity).getSuperEntity() == null
-                && entRes.lookupInheritanceTree(entity.getName()) == null;
+
+        if (!super.isIsolated(domain, entity)) {
+            return false;
+        }
+
+        if (((ObjEntity) entity).getSuperEntity() != null) {
+            return false;
+        }
+
+        // TODO: andrus 05/30/2010 - reindexing all DataMaps every time may be VERY slow
+        // on large projects
+        EntityResolver resolver = new EntityResolver(((DataChannelDescriptor) mediator
+                .getProject()
+                .getRootNode()).getDataMaps());
+
+        EntityInheritanceTree inheritanceTree = resolver.lookupInheritanceTree(entity
+                .getName());
+        return inheritanceTree == null || inheritanceTree.getChildren().isEmpty();
     }
 
     @Override