cayenne-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ntimof...@apache.org
Subject [1/4] cayenne git commit: CAY-2410 add prefetch type to sqlTemplate and selectQuery
Date Mon, 05 Mar 2018 08:14:20 GMT
Repository: cayenne
Updated Branches:
  refs/heads/master 7758dbf42 -> ec5df09b7


CAY-2410 add prefetch type to sqlTemplate and selectQuery


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/b3e513c4
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/b3e513c4
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/b3e513c4

Branch: refs/heads/master
Commit: b3e513c47efb75e1da726b21dba3b73be2bbdd91
Parents: 193c6aa
Author: Arseni Bulatski <ancarseni@gmail.com>
Authored: Fri Feb 23 11:34:42 2018 +0300
Committer: Arseni Bulatski <ancarseni@gmail.com>
Committed: Fri Feb 23 11:41:00 2018 +0300

----------------------------------------------------------------------
 RELEASE-NOTES.txt                               |   1 +
 .../validation/SelectQueryValidator.java        |   4 +-
 .../xml/QueryDescriptorHandler.java             |  29 +++-
 .../cayenne/map/QueryDescriptorLoader.java      |  15 +-
 .../cayenne/map/SQLTemplateDescriptor.java      |  38 ++---
 .../cayenne/map/SelectQueryDescriptor.java      |  62 ++++++--
 .../org/apache/cayenne/schema/10/modelMap.xsd   |  12 +-
 .../PrefetchTypeForSelectQueryHandlerTest.java  |  33 +++++
 .../PrefetchTypeForSqlTemplateHandlerTest.java  |  51 +++++++
 .../PrefetchTypeForSelectQueryHandlerTest.xml   |  25 ++++
 .../PrefetchTypeForSqlTemplateHandlerTest.xml   |  26 ++++
 .../modeler/editor/SQLTemplatePrefetchTab.java  | 147 +++++++++++++------
 .../modeler/editor/SelectQueryMainTab.java      |   2 +-
 .../modeler/editor/SelectQueryOrderingTab.java  |  67 ++++-----
 .../modeler/editor/SelectQueryPrefetchTab.java  | 139 +++++++++++++-----
 15 files changed, 486 insertions(+), 165 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index cfd075a..1153f26 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -24,6 +24,7 @@ CAY-2396 Upgrade maven-assembly-plugin to 3.1.0
 CAY-2403 Extract eventbridges to top level
 CAY-2404 Move itests to maven-plugins
 CAY-2407 Modeler: add prefetch support for the SQLTemplate query
+CAY-2410 Add prefetch type support for SQLTemplate query and SelectQuery
 
 Bug Fixes:
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-project/src/main/java/org/apache/cayenne/project/validation/SelectQueryValidator.java
----------------------------------------------------------------------
diff --git a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/SelectQueryValidator.java b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/SelectQueryValidator.java
index 908fae7..851897b 100644
--- a/cayenne-project/src/main/java/org/apache/cayenne/project/validation/SelectQueryValidator.java
+++ b/cayenne-project/src/main/java/org/apache/cayenne/project/validation/SelectQueryValidator.java
@@ -49,8 +49,8 @@ class SelectQueryValidator extends BaseQueryValidator {
                 validateOrdering(query, root, ordering, validationResult);
             }
 
-            if (query.getPrefetches() != null) {
-                for (String prefetchPath : query.getPrefetches()) {
+            if (query.getPrefetchesMap() != null) {
+                for (String prefetchPath : query.getPrefetchesMap().keySet()) {
                     validatePrefetch(root, prefetchPath, validationResult);
                 }
             }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/QueryDescriptorHandler.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/QueryDescriptorHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/QueryDescriptorHandler.java
index 1cff9eb..80c20b8 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/QueryDescriptorHandler.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/xml/QueryDescriptorHandler.java
@@ -52,6 +52,8 @@ public class QueryDescriptorHandler extends NamespaceAwareNestedTagHandler {
     private String descending;
     private String ignoreCase;
 
+    private int semantics;
+
     public QueryDescriptorHandler(NamespaceAwareNestedTagHandler parentHandler, DataMap map) {
         super(parentHandler);
         this.map = map;
@@ -80,6 +82,7 @@ public class QueryDescriptorHandler extends NamespaceAwareNestedTagHandler {
             case QUERY_EJBQL_TAG:
             case QUERY_QUALIFIER_TAG:
             case QUERY_PREFETCH_TAG:
+                createPrefetchSemantics(attributes);
                 return true;
         }
 
@@ -106,7 +109,7 @@ public class QueryDescriptorHandler extends NamespaceAwareNestedTagHandler {
                 break;
 
             case QUERY_PREFETCH_TAG:
-                queryBuilder.addPrefetch(data);
+                addPrefetchWithSemantics(data);
                 break;
         }
     }
@@ -180,6 +183,14 @@ public class QueryDescriptorHandler extends NamespaceAwareNestedTagHandler {
         changed = true;
     }
 
+    private void createPrefetchSemantics(Attributes attributes) {
+        semantics = convertPrefetchType(attributes.getValue("type"));
+    }
+
+    private void addPrefetchWithSemantics(String path) {
+        queryBuilder.addPrefetch(path, semantics);
+    }
+
     public QueryDescriptor getQueryDescriptor() {
         if(queryBuilder == null) {
             return null;
@@ -190,4 +201,20 @@ public class QueryDescriptorHandler extends NamespaceAwareNestedTagHandler {
         }
         return descriptor;
     }
+
+    private int convertPrefetchType(String type) {
+        if (type != null) {
+            switch (type) {
+                case "joint":
+                    return 1;
+                case "disjoint":
+                    return 2;
+                case "disjointById":
+                    return 3;
+                default:
+                    return 0;
+            }
+        }
+        return 0;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java
index 8b05207..785493e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java
@@ -52,7 +52,7 @@ public class QueryDescriptorLoader {
     protected String resultEntity;
 
     protected List<Ordering> orderings = new ArrayList<>();
-    protected List<String> prefetches = new ArrayList<>();
+    protected HashMap<String, Integer> prefetchesMap = new HashMap<>();
     protected Map<String, String> adapterSql = new HashMap<>();
     protected Map<String, String> properties = new HashMap<>();
 
@@ -71,11 +71,11 @@ public class QueryDescriptorLoader {
             case QueryDescriptor.SELECT_QUERY:
                 ((SelectQueryDescriptor) descriptor).setQualifier(qualifier);
                 ((SelectQueryDescriptor) descriptor).setOrderings(orderings);
-                ((SelectQueryDescriptor) descriptor).setPrefetches(prefetches);
+                ((SelectQueryDescriptor) descriptor).setPrefetchesMap(prefetchesMap);
                 break;
             case QueryDescriptor.SQL_TEMPLATE:
                 ((SQLTemplateDescriptor) descriptor).setSql(sql);
-                ((SQLTemplateDescriptor) descriptor).setPrefetches(prefetches);
+                ((SQLTemplateDescriptor) descriptor).setPrefetchesMap(prefetchesMap);
                 ((SQLTemplateDescriptor) descriptor).setAdapterSql(adapterSql);
                 break;
             case QueryDescriptor.EJBQL_QUERY:
@@ -234,15 +234,16 @@ public class QueryDescriptorLoader {
         orderings.add(new Ordering(path, order));
     }
 
-    public void addPrefetch(String path) {
+    public void addPrefetch(String path, int semantics) {
         if (path == null || (path != null && isBlank(path))) {
             // throw??
             return;
         }
 
-        if (prefetches == null) {
-            prefetches = new ArrayList<>();
+        if (prefetchesMap == null) {
+            prefetchesMap = new HashMap<>();
         }
-        prefetches.add(path.trim());
+
+        prefetchesMap.put(path.trim(), semantics);
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
index e3a0709..6733fd4 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
@@ -23,9 +23,7 @@ import org.apache.cayenne.query.PrefetchTreeNode;
 import org.apache.cayenne.query.SQLTemplate;
 import org.apache.cayenne.util.XMLEncoder;
 
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.TreeSet;
 
@@ -35,7 +33,7 @@ import java.util.TreeSet;
 public class SQLTemplateDescriptor extends QueryDescriptor {
 
     protected String sql;
-    protected List<String> prefetches = new ArrayList<>();
+    protected HashMap<String, Integer> prefetchesMap = new HashMap<>();
 
     protected Map<String, String> adapterSql = new HashMap<>();
 
@@ -72,31 +70,33 @@ public class SQLTemplateDescriptor extends QueryDescriptor {
     }
 
     /**
-     * Returns list of prefetch paths for this query.
+     * Returns map of prefetch paths with semantics for this query.
+     * @since 4.1
      */
-    public List<String> getPrefetches() {
-        return prefetches;
-    }
+    public HashMap<String, Integer> getPrefetchesMap() { return prefetchesMap; }
 
     /**
-     * Sets list of prefetch paths for this query.
+     * Sets map of prefetch paths with semantics for this query.
+     * @since 4.1
      */
-    public void setPrefetches(List<String> prefetches) {
-        this.prefetches = prefetches;
+    public void setPrefetchesMap(HashMap<String, Integer> prefetchesMap) {
+        this.prefetchesMap = prefetchesMap;
     }
 
     /**
-     * Adds single prefetch path to this query.
+     * Adds single prefetch path with semantics to this query.
+     * @since 4.1
      */
-    public void addPrefetch(String prefetchPath) {
-        this.prefetches.add(prefetchPath);
+    public void addPrefetch(String prefetchPath, int semantics){
+        this.prefetchesMap.put(prefetchPath, semantics);
     }
 
     /**
      * Removes single prefetch path from this query.
+     * @since 4.1
      */
     public void removePrefetch(String prefetchPath) {
-        this.prefetches.remove(prefetchPath);
+        this.prefetchesMap.remove(prefetchPath);
     }
 
     @Override
@@ -109,10 +109,10 @@ public class SQLTemplateDescriptor extends QueryDescriptor {
 
 
 
-        List<String> prefetches = this.getPrefetches();
+        HashMap<String, Integer> prefetches = this.getPrefetchesMap();
         if (prefetches != null && !prefetches.isEmpty()) {
-            for (String prefetch : prefetches) {
-                template.addPrefetch(PrefetchTreeNode.withPath(prefetch, PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS));
+            for (String prefetch : prefetches.keySet()) {
+                template.addPrefetch(PrefetchTreeNode.withPath(prefetch, prefetchesMap.get(prefetch)));
             }
         }
 
@@ -196,9 +196,9 @@ public class SQLTemplateDescriptor extends QueryDescriptor {
 
         PrefetchTreeNode prefetchTree = new PrefetchTreeNode();
 
-        for (String prefetchPath : prefetches) {
+        for (String prefetchPath : prefetchesMap.keySet()) {
             PrefetchTreeNode node = prefetchTree.addPath(prefetchPath);
-            node.setSemantics(PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS);
+            node.setSemantics(prefetchesMap.get(prefetchPath));
             node.setPhantom(false);
         }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-server/src/main/java/org/apache/cayenne/map/SelectQueryDescriptor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/SelectQueryDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/map/SelectQueryDescriptor.java
index e9c9b5d..fa1590a 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/SelectQueryDescriptor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/SelectQueryDescriptor.java
@@ -26,6 +26,7 @@ import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.util.XMLEncoder;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -38,7 +39,7 @@ public class SelectQueryDescriptor extends QueryDescriptor {
 	protected Expression qualifier;
 
     protected List<Ordering> orderings = new ArrayList<>();
-    protected List<String> prefetches = new ArrayList<>();
+    protected HashMap<String, Integer> prefetchesMap = new HashMap<>();
 
     public SelectQueryDescriptor() {
         super(SELECT_QUERY);
@@ -97,31 +98,69 @@ public class SelectQueryDescriptor extends QueryDescriptor {
     }
 
     /**
+     * Returns map of prefetch paths with semantics for this query.
+     *
+     * @since 4.1
+     */
+    public HashMap<String, Integer> getPrefetchesMap() {
+        return prefetchesMap;
+    }
+
+    /**
      * Returns list of prefetch paths for this query.
+     *
+     * @deprecated since 4.1 use {@link #getPrefetchesMap()}.
      */
+    @Deprecated
     public List<String> getPrefetches() {
-        return prefetches;
+        return new ArrayList<>(prefetchesMap.keySet());
+    }
+
+    /**
+     * Sets map of prefetch paths with semantics for this query.
+     *
+     * @since 4.1
+     */
+    public void setPrefetchesMap(HashMap<String, Integer> prefetchesMap){
+        this.prefetchesMap = prefetchesMap;
     }
 
     /**
      * Sets list of prefetch paths for this query.
+     *
+     * @deprecated since 4.1 use {@link #setPrefetchesMap(HashMap)}.
      */
+    @Deprecated
     public void setPrefetches(List<String> prefetches) {
-        this.prefetches = prefetches;
+        for(String prefetch : prefetches){
+            this.prefetchesMap.put(prefetch, PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+        }
+    }
+
+    /**
+     * Adds prefetch path with semantics to this query.
+     *
+     * @since 4.1
+     */
+    public void addPrefetch(String prefetchPath, int semantics){
+        this.prefetchesMap.put(prefetchPath, semantics);
     }
 
     /**
      * Adds single prefetch path to this query.
+     *
+     * @deprecated since 4.1 use {@link #addPrefetch(String, int)}
      */
+    @Deprecated
     public void addPrefetch(String prefetchPath) {
-        this.prefetches.add(prefetchPath);
+        this.prefetchesMap.put(prefetchPath, PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
     }
 
     /**
      * Removes single prefetch path from this query.
      */
     public void removePrefetch(String prefetchPath) {
-        this.prefetches.remove(prefetchPath);
+        this.prefetchesMap.remove(prefetchPath);
     }
 
     @Override
@@ -136,11 +175,10 @@ public class SelectQueryDescriptor extends QueryDescriptor {
             selectQuery.addOrderings(orderings);
         }
 
-        List<String> prefetches = this.getPrefetches();
-
-        if (prefetches != null && !prefetches.isEmpty()) {
-            for (String prefetch : prefetches) {
-                selectQuery.addPrefetch(prefetch);
+        HashMap<String, Integer> prefetchesMap = this.getPrefetchesMap();
+        if(prefetchesMap != null && !prefetchesMap.isEmpty()) {
+            for(String prefetch : prefetchesMap.keySet()) {
+                selectQuery.addPrefetch(PrefetchTreeNode.withPath(prefetch, prefetchesMap.get(prefetch)));
             }
         }
 
@@ -193,9 +231,9 @@ public class SelectQueryDescriptor extends QueryDescriptor {
 
         PrefetchTreeNode prefetchTree = new PrefetchTreeNode();
 
-        for (String prefetchPath : prefetches) {
+        for (String prefetchPath : prefetchesMap.keySet()) {
             PrefetchTreeNode node = prefetchTree.addPath(prefetchPath);
-            node.setSemantics(PrefetchTreeNode.UNDEFINED_SEMANTICS);
+            node.setSemantics(prefetchesMap.get(prefetchPath));
             node.setPhantom(false);
         }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-server/src/main/resources/org/apache/cayenne/schema/10/modelMap.xsd
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/resources/org/apache/cayenne/schema/10/modelMap.xsd b/cayenne-server/src/main/resources/org/apache/cayenne/schema/10/modelMap.xsd
index 7f36483..543c0a6 100644
--- a/cayenne-server/src/main/resources/org/apache/cayenne/schema/10/modelMap.xsd
+++ b/cayenne-server/src/main/resources/org/apache/cayenne/schema/10/modelMap.xsd
@@ -185,7 +185,7 @@
 				<xs:element minOccurs="0" maxOccurs="unbounded" ref="cay:ejbql"/>
 				<xs:element name="qualifier" minOccurs="0" maxOccurs="unbounded" type="xs:string"/>
 				<xs:element minOccurs="0" maxOccurs="unbounded" ref="cay:ordering"/>
-				<xs:element name="prefetch" minOccurs="0" maxOccurs="unbounded" type="xs:string"/>
+				<xs:element minOccurs="0" maxOccurs="unbounded" ref="cay:prefetch"/>
 				<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other" processContents="lax"/>
 			</xs:sequence>
 			<xs:attribute name="type" use="required" type="xs:string"/>
@@ -207,6 +207,16 @@
 		</xs:complexType>
 	</xs:element>
 
+	<xs:element name="prefetch">
+		<xs:complexType>
+			<xs:simpleContent>
+				<xs:extension base="xs:string">
+					<xs:attribute name="type" type="xs:string"/>
+				</xs:extension>
+			</xs:simpleContent>
+		</xs:complexType>
+	</xs:element>
+
 	<xs:element name="sql">
 		<xs:annotation>
 			<xs:documentation>Defines arbitrary SQL statement. Note that SQL statement can be customized for different SQL dialects per DbAdapter class. If no adapter-specific statement is found, the one with no adapter label is used by default.</xs:documentation>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/PrefetchTypeForSelectQueryHandlerTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/PrefetchTypeForSelectQueryHandlerTest.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/PrefetchTypeForSelectQueryHandlerTest.java
new file mode 100644
index 0000000..0a75c50
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/PrefetchTypeForSelectQueryHandlerTest.java
@@ -0,0 +1,33 @@
+package org.apache.cayenne.configuration.xml;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.SelectQueryDescriptor;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @since 4.1
+ */
+public class PrefetchTypeForSelectQueryHandlerTest extends BaseHandlerTest{
+
+    @Test
+    public void testLoad() throws Exception {
+        final DataMap map = new DataMap();
+
+        parse("query", new HandlerFactory() {
+            @Override
+            public NamespaceAwareNestedTagHandler createHandler(NamespaceAwareNestedTagHandler parent) {
+                return new QueryDescriptorHandler(parent, map);
+            }
+        });
+
+        SelectQueryDescriptor selectQueryDescriptor = (SelectQueryDescriptor) map.getQueryDescriptor("query");
+        assertEquals(3, selectQueryDescriptor.getPrefetchesMap().size());
+
+        assertEquals(1, (int) selectQueryDescriptor.getPrefetchesMap().get("paintings"));
+        assertEquals(2, (int) selectQueryDescriptor.getPrefetchesMap().get("paintings.artist"));
+        assertEquals(3, (int) selectQueryDescriptor.getPrefetchesMap().get("paintings.gallery"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/PrefetchTypeForSqlTemplateHandlerTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/PrefetchTypeForSqlTemplateHandlerTest.java b/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/PrefetchTypeForSqlTemplateHandlerTest.java
new file mode 100644
index 0000000..57bc71a
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/configuration/xml/PrefetchTypeForSqlTemplateHandlerTest.java
@@ -0,0 +1,51 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.configuration.xml;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.SQLTemplateDescriptor;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @since 4.1
+ */
+public class PrefetchTypeForSqlTemplateHandlerTest extends BaseHandlerTest {
+
+    @Test
+    public void testLoad() throws Exception {
+        final DataMap map = new DataMap();
+
+        parse("query", new HandlerFactory() {
+            @Override
+            public NamespaceAwareNestedTagHandler createHandler(NamespaceAwareNestedTagHandler parent) {
+                return new QueryDescriptorHandler(parent, map);
+            }
+        });
+
+        SQLTemplateDescriptor sqlTemplateDescriptor = (SQLTemplateDescriptor) map.getQueryDescriptor("query");
+        assertEquals(3, sqlTemplateDescriptor.getPrefetchesMap().size());
+
+        assertEquals(1, (int) sqlTemplateDescriptor.getPrefetchesMap().get("paintings"));
+        assertEquals(2, (int) sqlTemplateDescriptor.getPrefetchesMap().get("paintings.artist"));
+        assertEquals(3, (int) sqlTemplateDescriptor.getPrefetchesMap().get("paintings.gallery"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/PrefetchTypeForSelectQueryHandlerTest.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/PrefetchTypeForSelectQueryHandlerTest.xml b/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/PrefetchTypeForSelectQueryHandlerTest.xml
new file mode 100644
index 0000000..fde31e0
--- /dev/null
+++ b/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/PrefetchTypeForSelectQueryHandlerTest.xml
@@ -0,0 +1,25 @@
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~   Licensed to the Apache Software Foundation (ASF) under one
+  ~  or more contributor license agreements.  See the NOTICE file
+  ~  distributed with this work for additional information
+  ~  regarding copyright ownership.  The ASF licenses this file
+  ~  to you under the Apache License, Version 2.0 (the
+  ~  "License"); you may not use this file except in compliance
+  ~  with the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing,
+  ~  software distributed under the License is distributed on an
+  ~  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~  KIND, either express or implied.  See the License for the
+  ~  specific language governing permissions and limitations
+  ~  under the License.
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+
+<query name="query" type="SelectQuery" root="obj-entity" root-name="Artist">
+    <property name="cayenne.GenericSelectQuery.fetchingDataRows" value="false"/>
+    <prefetch type="joint"><![CDATA[paintings]]></prefetch>
+    <prefetch type="disjoint"><![CDATA[paintings.artist]]></prefetch>
+    <prefetch type="disjointById"><![CDATA[paintings.gallery]]></prefetch>
+</query>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/PrefetchTypeForSqlTemplateHandlerTest.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/PrefetchTypeForSqlTemplateHandlerTest.xml b/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/PrefetchTypeForSqlTemplateHandlerTest.xml
new file mode 100644
index 0000000..0f1e502
--- /dev/null
+++ b/cayenne-server/src/test/resources/org/apache/cayenne/configuration/xml/PrefetchTypeForSqlTemplateHandlerTest.xml
@@ -0,0 +1,26 @@
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~   Licensed to the Apache Software Foundation (ASF) under one
+  ~  or more contributor license agreements.  See the NOTICE file
+  ~  distributed with this work for additional information
+  ~  regarding copyright ownership.  The ASF licenses this file
+  ~  to you under the Apache License, Version 2.0 (the
+  ~  "License"); you may not use this file except in compliance
+  ~  with the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing,
+  ~  software distributed under the License is distributed on an
+  ~  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~  KIND, either express or implied.  See the License for the
+  ~  specific language governing permissions and limitations
+  ~  under the License.
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+
+<query name="query" type="SQLTemplate" root="obj-entity" root-name="Artist">
+    <property name="cayenne.GenericSelectQuery.fetchingDataRows" value="false"/>
+    <sql><![CDATA[select * from Artist]]></sql>
+    <prefetch type="joint"><![CDATA[paintings]]></prefetch>
+    <prefetch type="disjoint"><![CDATA[paintings.artist]]></prefetch>
+    <prefetch type="disjointById"><![CDATA[paintings.gallery]]></prefetch>
+</query>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
index 0398eee..49f8a67 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
@@ -41,8 +41,10 @@ import org.apache.cayenne.swing.components.image.FilteredIconFactory;
 import org.apache.cayenne.util.CayenneMapEntry;
 
 import javax.swing.BorderFactory;
+import javax.swing.DefaultCellEditor;
 import javax.swing.Icon;
 import javax.swing.JButton;
+import javax.swing.JComboBox;
 import javax.swing.JComponent;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
@@ -51,32 +53,35 @@ import javax.swing.JSplitPane;
 import javax.swing.JTable;
 import javax.swing.JToolBar;
 import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
 import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableColumn;
 import javax.swing.table.TableModel;
 import javax.swing.tree.TreeModel;
 import java.awt.BorderLayout;
 import java.awt.CardLayout;
 import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.prefs.Preferences;
 
+/**
+ * Class configured to work with prefetches.
+ */
 public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeListener {
 
     // property for split pane divider size
     private static final String SPLIT_DIVIDER_LOCATION_PROPERTY = "query.orderings.divider.location";
 
+    private static final String JOINT_PREFETCH_SEMANTICS = "Joint";
+    private static final String DISJOINT_BY_ID_PREFETCH_SEMANTICS = "Disjoint by id";
+    private static final String UNDEFINED_SEMANTICS = "Undefined semantics";
+
     static final Dimension BROWSER_CELL_DIM = new Dimension(150, 100);
     static final Dimension TABLE_DIM = new Dimension(460, 60);
 
-    static final String PATH_HEADER = "Path";
-    static final String ASCENDING_HEADER = "Ascending";
-    static final String IGNORE_CASE_HEADER = "Ignore Case";
-
     static final String REAL_PANEL = "real";
     static final String PLACEHOLDER_PANEL = "placeholder";
 
@@ -97,7 +102,6 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
     }
 
     protected void initView() {
-
         messagePanel = new JPanel(new BorderLayout());
         cardLayout = new CardLayout();
 
@@ -122,14 +126,10 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
     }
 
     protected void initController() {
-
         // scroll to selected row whenever a selection even occurs
-        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
-
-            public void valueChanged(ListSelectionEvent e) {
-                if (!e.getValueIsAdjusting()) {
-                    UIUtil.scrollToSelectedRow(table);
-                }
+        table.getSelectionModel().addListSelectionListener(e -> {
+            if (!e.getValueIsAdjusting()) {
+                UIUtil.scrollToSelectedRow(table);
             }
         });
     }
@@ -149,7 +149,9 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
 
         this.sqlTemplate = (SQLTemplateDescriptor) query;
         browser.setModel(createBrowserModel((Entity) sqlTemplate.getRoot()));
+
         table.setModel(createTableModel());
+        setUpPrefetchBox(table.getColumnModel().getColumn(2));
 
         // init column sizes
         table.getColumnModel().getColumn(0).setPreferredWidth(250);
@@ -165,6 +167,22 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
         cardLayout.show(this, PLACEHOLDER_PANEL);
     }
 
+    protected void setUpPrefetchBox(TableColumn column) {
+
+        JComboBox prefetchBox = new JComboBox();
+        prefetchBox.addItem(JOINT_PREFETCH_SEMANTICS);
+        prefetchBox.addItem(DISJOINT_BY_ID_PREFETCH_SEMANTICS);
+
+        prefetchBox.addActionListener(e -> Application.getInstance().getFrameController().getEditorView().getEventController().setDirty(true));
+
+        column.setCellEditor(new DefaultCellEditor(prefetchBox));
+
+        DefaultTableCellRenderer renderer =
+                new DefaultTableCellRenderer();
+        renderer.setToolTipText("Click for combo box");
+        column.setCellRenderer(renderer);
+    }
+
     protected JPanel createEditorPanel() {
 
         table = new JTable();
@@ -180,6 +198,7 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
     }
 
     protected JPanel createSelectorPanel() {
+
         browser = new MultiColumnBrowser();
         browser.setPreferredColumnSize(BROWSER_CELL_DIM);
         browser.setDefaultRenderer();
@@ -206,19 +225,16 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
         add.setIcon(addIcon);
         add.setDisabledIcon(FilteredIconFactory.createDisabledIcon(addIcon));
 
-        add.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                String prefetch = getSelectedPath();
-
-                if (prefetch == null) {
-                    return;
-                }
-
-                addPrefetch(prefetch);
+        add.addActionListener(e -> {
+            String prefetch = getSelectedPath();
 
-                Application.getInstance().getUndoManager().addEdit(new AddPrefetchUndoableEditForSqlTemplate(prefetch, SQLTemplatePrefetchTab.this));
+            if (prefetch == null) {
+                return;
             }
 
+            addPrefetch(prefetch);
+
+            Application.getInstance().getUndoManager().addEdit(new AddPrefetchUndoableEditForSqlTemplate(prefetch, SQLTemplatePrefetchTab.this));
         });
 
         JButton remove = new CayenneAction.CayenneToolbarButton(null, 3);
@@ -227,20 +243,13 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
         remove.setIcon(removeIcon);
         remove.setDisabledIcon(FilteredIconFactory.createDisabledIcon(removeIcon));
 
-        remove.addActionListener(new ActionListener() {
-
-            public void actionPerformed(ActionEvent e) {
-                int selection = table.getSelectedRow();
-
-                if (selection < 0) {
-                    return;
-                }
-
-                String prefetch = (String) table.getModel().getValueAt(selection, 0);
-
-                removePrefetch(prefetch);
+        remove.addActionListener(e -> {
+            int selection = table.getSelectedRow();
+            if (selection < 0) {
+                return;
             }
-
+            String prefetch = (String) table.getModel().getValueAt(selection, 0);
+            removePrefetch(prefetch);
         });
 
         JToolBar toolBar = new JToolBar();
@@ -252,6 +261,7 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
     }
 
     protected String getSelectedPath() {
+
         Object[] path = browser.getSelectionPath().getPath();
 
         // first item in the path is Entity, so we must have
@@ -275,6 +285,7 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
     }
 
     protected TreeModel createBrowserModel(Entity entity) {
+
         EntityTreeModel treeModel = new EntityTreeModel(entity);
         treeModel.setFilter(
                 new EntityTreeFilter() {
@@ -296,14 +307,16 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
     public void addPrefetch(String prefetch) {
 
         // check if such prefetch already exists
-        if (!sqlTemplate.getPrefetches().isEmpty() && sqlTemplate.getPrefetches().contains(prefetch)) {
+        if (!sqlTemplate.getPrefetchesMap().isEmpty() && sqlTemplate.getPrefetchesMap().containsKey(prefetch)) {
             return;
         }
 
-        sqlTemplate.addPrefetch(prefetch);
+        //default value is joint
+        sqlTemplate.addPrefetch(prefetch, getPrefetchType(DISJOINT_BY_ID_PREFETCH_SEMANTICS));
 
         // reset the model, since it is immutable
         table.setModel(createTableModel());
+        setUpPrefetchBox(table.getColumnModel().getColumn(2));
 
         mediator.fireQueryEvent(new QueryEvent(this, sqlTemplate));
     }
@@ -313,6 +326,8 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
 
         // reset the model, since it is immutable
         table.setModel(createTableModel());
+        setUpPrefetchBox(table.getColumnModel().getColumn(2));
+
         mediator.fireQueryEvent(new QueryEvent(this, sqlTemplate));
     }
 
@@ -358,8 +373,30 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
         return SPLIT_DIVIDER_LOCATION_PROPERTY;
     }
 
+    protected int getPrefetchType(String semantics) {
+
+        //case 2: disjoint isn't use for SQLTemplate prefetch
+        switch (semantics){
+            case "Joint" :
+                return 1;
+            case "Disjoint by id":
+                return 3;
+            default: return 0;
+        }
+    }
+
+    protected String getPrefetchTypeString(int semantics) {
+        switch (semantics){
+            case 1 :
+                return JOINT_PREFETCH_SEMANTICS;
+            case 3:
+                return DISJOINT_BY_ID_PREFETCH_SEMANTICS;
+            default: return UNDEFINED_SEMANTICS;
+        }
+    }
+
     /**
-     * A table model for the Ordering editing table.
+     * A table model for the Prefetch table.
      */
     final class PrefetchModel extends AbstractTableModel {
 
@@ -367,16 +404,16 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
 
         PrefetchModel() {
             if (sqlTemplate != null) {
-                prefetches = new String[sqlTemplate.getPrefetches().size()];
-
-                for (int i = 0; i < prefetches.length; i++) {
-                    prefetches[i] = sqlTemplate.getPrefetches().get(i);
+                prefetches = new String[sqlTemplate.getPrefetchesMap().size()];
+                List<String> list = new ArrayList<>(sqlTemplate.getPrefetchesMap().keySet());
+                for(int i = 0; i < list.size(); i++){
+                    prefetches[i] = list.get(i);
                 }
             }
         }
 
         public int getColumnCount() {
-            return 2;
+            return 3;
         }
 
         public int getRowCount() {
@@ -389,6 +426,8 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
                     return prefetches[row];
                 case 1:
                     return isToMany(prefetches[row]) ? Boolean.TRUE : Boolean.FALSE;
+                case 2:
+                    return getPrefetchTypeString(sqlTemplate.getPrefetchesMap().get(prefetches[row]));
                 default:
                     throw new IndexOutOfBoundsException("Invalid column: " + column);
             }
@@ -400,6 +439,8 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
                     return String.class;
                 case 1:
                     return Boolean.class;
+                case 2:
+                    return String.class;
                 default:
                     throw new IndexOutOfBoundsException("Invalid column: " + column);
             }
@@ -411,13 +452,23 @@ public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeList
                     return "Prefetch Path";
                 case 1:
                     return "To Many";
+                case 2:
+                    return "Prefetch Type";
                 default:
                     throw new IndexOutOfBoundsException("Invalid column: " + column);
             }
         }
 
         public boolean isCellEditable(int row, int column) {
-            return false;
+            return column == 2 ? true : false;
+        }
+
+        public void setValueAt(Object value, int row, int column) {
+            switch (column) {
+                case 2:
+                    sqlTemplate.addPrefetch(prefetches[row],getPrefetchType((String)value));
+                    break;
+            }
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
index e68d17a..6c3ceac 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
@@ -45,6 +45,7 @@ import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.QueryDescriptor;
 import org.apache.cayenne.map.SelectQueryDescriptor;
 import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.swing.components.JCayenneCheckBox;
 import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.modeler.util.CellRenderers;
@@ -55,7 +56,6 @@ import org.apache.cayenne.modeler.util.TextAdapter;
 import org.apache.cayenne.modeler.util.ValidatorTextAdapter;
 import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 import org.apache.cayenne.project.extension.info.ObjectInfo;
-import org.apache.cayenne.query.*;
 import org.apache.cayenne.util.CayenneMapEntry;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryOrderingTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryOrderingTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryOrderingTab.java
index d6b7c4e..3c6b665 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryOrderingTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryOrderingTab.java
@@ -19,32 +19,6 @@
 
 package org.apache.cayenne.modeler.editor;
 
-import java.awt.BorderLayout;
-import java.awt.CardLayout;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.prefs.Preferences;
-
-import javax.swing.BorderFactory;
-import javax.swing.Icon;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-import javax.swing.JTable;
-import javax.swing.JToolBar;
-import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.table.AbstractTableModel;
-import javax.swing.table.TableModel;
-import javax.swing.tree.TreeModel;
-
 import org.apache.cayenne.configuration.event.QueryEvent;
 import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.QueryDescriptor;
@@ -61,12 +35,36 @@ import org.apache.cayenne.query.SortOrder;
 import org.apache.cayenne.swing.components.image.FilteredIconFactory;
 import org.apache.cayenne.util.CayenneMapEntry;
 
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.JToolBar;
+import javax.swing.ListSelectionModel;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.tree.TreeModel;
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.prefs.Preferences;
+
 /**
  * A panel for picking SelectQuery orderings.
  * 
  */
 public class SelectQueryOrderingTab extends JPanel implements PropertyChangeListener {
 
+
     // property for split pane divider size
     private static final String SPLIT_DIVIDER_LOCATION_PROPERTY = "query.orderings.divider.location";
 
@@ -124,12 +122,9 @@ public class SelectQueryOrderingTab extends JPanel implements PropertyChangeList
     protected void initController() {
 
         // scroll to selected row whenever a selection even occurs
-        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
-
-            public void valueChanged(ListSelectionEvent e) {
-                if (!e.getValueIsAdjusting()) {
-                    UIUtil.scrollToSelectedRow(table);
-                }
+        table.getSelectionModel().addListSelectionListener(e -> {
+            if (!e.getValueIsAdjusting()) {
+                UIUtil.scrollToSelectedRow(table);
             }
         });
     }
@@ -205,13 +200,7 @@ public class SelectQueryOrderingTab extends JPanel implements PropertyChangeList
         Icon addIcon = ModelerUtil.buildIcon("icon-plus.png");
         add.setIcon(addIcon);
         add.setDisabledIcon(FilteredIconFactory.createDisabledIcon(addIcon));
-        add.addActionListener(new ActionListener() {
-
-            public void actionPerformed(ActionEvent e) {
-                addOrdering();
-            }
-
-        });
+        add.addActionListener(e -> addOrdering());
 
         JButton remove = new CayenneAction.CayenneToolbarButton(null, 3);
         remove.setText("Remove Ordering");

http://git-wip-us.apache.org/repos/asf/cayenne/blob/b3e513c4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java
index 2a24789..c75b6eb 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java
@@ -35,12 +35,20 @@ import org.apache.cayenne.modeler.util.EntityTreeModel;
 import org.apache.cayenne.modeler.util.ModelerUtil;
 import org.apache.cayenne.swing.components.image.FilteredIconFactory;
 
-import javax.swing.*;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultCellEditor;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JToolBar;
 import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableColumn;
 import javax.swing.table.TableModel;
 import javax.swing.tree.TreeModel;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Subclass of the SelectQueryOrderingTab configured to work with prefetches.
@@ -48,10 +56,37 @@ import java.awt.event.ActionListener;
  */
 public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
 
+    private static final String JOINT_PREFETCH_SEMANTICS = "Joint";
+    private static final String DISJOINT_PREFETCH_SEMANTICS = "Disjoint";
+    private static final String DISJOINT_BY_ID_PREFETCH_SEMANTICS = "Disjoint by id";
+    private static final String UNDEFINED_SEMANTICS = "Undefined semantics";
+
     public SelectQueryPrefetchTab(ProjectController mediator) {
         super(mediator);
     }
 
+    protected void initFromModel(){
+        super.initFromModel();
+        setUpPrefetchBox(table.getColumnModel().getColumn(2));
+    }
+
+    protected void setUpPrefetchBox(TableColumn column) {
+
+        JComboBox prefetchBox = new JComboBox();
+        prefetchBox.addItem(JOINT_PREFETCH_SEMANTICS);
+        prefetchBox.addItem(DISJOINT_PREFETCH_SEMANTICS);
+        prefetchBox.addItem(DISJOINT_BY_ID_PREFETCH_SEMANTICS);
+
+        prefetchBox.addActionListener(e -> Application.getInstance().getFrameController().getEditorView().getEventController().setDirty(true));
+
+        column.setCellEditor(new DefaultCellEditor(prefetchBox));
+
+        DefaultTableCellRenderer renderer =
+                new DefaultTableCellRenderer();
+        renderer.setToolTipText("Click for combo box");
+        column.setCellRenderer(renderer);
+    }
+
     protected JComponent createToolbar() {
 
         JButton add = new CayenneAction.CayenneToolbarButton(null, 1);
@@ -60,19 +95,16 @@ public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
         add.setIcon(addIcon);
         add.setDisabledIcon(FilteredIconFactory.createDisabledIcon(addIcon));
         
-        add.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-            	String prefetch = getSelectedPath();
-                
-            	if (prefetch == null) {
-                    return;
-                }
-            	
-                addPrefetch(prefetch);
-                
-                Application.getInstance().getUndoManager().addEdit(new AddPrefetchUndoableEdit(prefetch, SelectQueryPrefetchTab.this));
+        add.addActionListener(e -> {
+            String prefetch = getSelectedPath();
+
+            if (prefetch == null) {
+                return;
             }
 
+            addPrefetch(prefetch);
+
+            Application.getInstance().getUndoManager().addEdit(new AddPrefetchUndoableEdit(prefetch, SelectQueryPrefetchTab.this));
         });
 
         JButton remove = new CayenneAction.CayenneToolbarButton(null, 3);
@@ -81,20 +113,16 @@ public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
         remove.setIcon(removeIcon);
         remove.setDisabledIcon(FilteredIconFactory.createDisabledIcon(removeIcon));
         
-        remove.addActionListener(new ActionListener() {
+        remove.addActionListener(e -> {
+            int selection = table.getSelectedRow();
 
-            public void actionPerformed(ActionEvent e) {
-            	int selection = table.getSelectedRow();
-                
-            	if (selection < 0) {
-                    return;
-                }
-
-            	String prefetch = (String) table.getModel().getValueAt(selection, 0);
-            	
-                removePrefetch(prefetch);
+            if (selection < 0) {
+                return;
             }
 
+            String prefetch = (String) table.getModel().getValueAt(selection, 0);
+
+            removePrefetch(prefetch);
         });
 
         JToolBar toolBar = new JToolBar();
@@ -127,14 +155,16 @@ public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
     public void addPrefetch(String prefetch) {
         
         // check if such prefetch already exists
-        if (!selectQuery.getPrefetches().isEmpty() && selectQuery.getPrefetches().contains(prefetch)) {
+        if (!selectQuery.getPrefetchesMap().isEmpty() && selectQuery.getPrefetchesMap().containsKey(prefetch)) {
             return;
         }
 
-        selectQuery.addPrefetch(prefetch);
+        //default value id disjoint
+        selectQuery.addPrefetch(prefetch, getPrefetchType(DISJOINT_PREFETCH_SEMANTICS));
        
         // reset the model, since it is immutable
         table.setModel(createTableModel());
+        setUpPrefetchBox(table.getColumnModel().getColumn(2));
         
         mediator.fireQueryEvent(new QueryEvent(this, selectQuery));
     }
@@ -144,6 +174,8 @@ public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
 
         // reset the model, since it is immutable
         table.setModel(createTableModel());
+        setUpPrefetchBox(table.getColumnModel().getColumn(2));
+
         mediator.fireQueryEvent(new QueryEvent(this, selectQuery));
     }
 
@@ -170,8 +202,32 @@ public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
         }
     }
 
+    protected int getPrefetchType(String semantics) {
+        switch (semantics){
+            case "Joint" :
+                return 1;
+            case "Disjoint":
+                return 2;
+            case "Disjoint by id":
+                return 3;
+            default: return 0;
+        }
+    }
+
+    protected String getPrefetchTypeString(int semantics) {
+        switch (semantics){
+            case 1 :
+                return JOINT_PREFETCH_SEMANTICS;
+            case 2:
+                return DISJOINT_PREFETCH_SEMANTICS;
+            case 3:
+                return DISJOINT_BY_ID_PREFETCH_SEMANTICS;
+            default: return UNDEFINED_SEMANTICS;
+        }
+    }
+
     /**
-     * A table model for the Ordering editing table.
+     * A table model for the Prefetch table.
      */
     final class PrefetchModel extends AbstractTableModel {
 
@@ -179,16 +235,16 @@ public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
 
         PrefetchModel() {
             if (selectQuery != null) {
-                prefetches = new String[selectQuery.getPrefetches().size()];
-
-                for (int i = 0; i < prefetches.length; i++) {
-                    prefetches[i] = selectQuery.getPrefetches().get(i);
+                prefetches = new String[selectQuery.getPrefetchesMap().size()];
+                List<String> list = new ArrayList<>(selectQuery.getPrefetchesMap().keySet());
+                for(int i = 0; i < list.size(); i++) {
+                    prefetches[i] = list.get(i);
                 }
             }
         }
 
         public int getColumnCount() {
-            return 2;
+            return 3;
         }
 
         public int getRowCount() {
@@ -201,6 +257,8 @@ public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
                     return prefetches[row];
                 case 1:
                     return isToMany(prefetches[row]) ? Boolean.TRUE : Boolean.FALSE;
+                case 2:
+                    return getPrefetchTypeString(selectQuery.getPrefetchesMap().get(prefetches[row]));
                 default:
                     throw new IndexOutOfBoundsException("Invalid column: " + column);
             }
@@ -212,6 +270,8 @@ public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
                     return String.class;
                 case 1:
                     return Boolean.class;
+                case 2:
+                    return String.class;
                 default:
                     throw new IndexOutOfBoundsException("Invalid column: " + column);
             }
@@ -223,13 +283,22 @@ public class SelectQueryPrefetchTab extends SelectQueryOrderingTab {
                     return "Prefetch Path";
                 case 1:
                     return "To Many";
+                case 2:
+                    return "Prefetch Type";
                 default:
-                    throw new IndexOutOfBoundsException("Invalid column: " + column);
+                    throw new IndexOutOfBoundsException("Invalid columnw: " + column);
             }
         }
 
         public boolean isCellEditable(int row, int column) {
-            return false;
+            return column == 2 ? true : false;
+        }
+        public void setValueAt(Object value, int row, int column){
+            switch (column) {
+                case 2:
+                    selectQuery.addPrefetch(prefetches[row], getPrefetchType((String)value));
+                    break;
+            }
         }
     }
 }


Mime
View raw message