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/06/05 03:09:44 UTC

svn commit: r951630 - in /cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test: java/org/apache/cayenne/access/ java/org/apache/cayenne/testdo/inheritance/vertical/auto/ resources/

Author: aadamchik
Date: Sat Jun  5 01:09:43 2010
New Revision: 951630

URL: http://svn.apache.org/viewvc?rev=951630&view=rev
Log:
CAY-1090 vertical inheritance

(implementing via common root + flattened attributes)

* select unit tests
* insert unit tests
* delete unit tests

Modified:
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/VerticalInheritanceTest.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/inheritance/vertical/auto/_IvRoot.java
    cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/inheritance-vertical.map.xml

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/VerticalInheritanceTest.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/VerticalInheritanceTest.java?rev=951630&r1=951629&r2=951630&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/VerticalInheritanceTest.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/access/VerticalInheritanceTest.java Sat Jun  5 01:09:43 2010
@@ -18,10 +18,18 @@
  ****************************************************************/
 package org.apache.cayenne.access;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.test.DBHelper;
 import org.apache.cayenne.test.TableHelper;
 import org.apache.cayenne.testdo.inheritance.vertical.IvRoot;
+import org.apache.cayenne.testdo.inheritance.vertical.IvSub1;
+import org.apache.cayenne.testdo.inheritance.vertical.IvSub1Sub1;
+import org.apache.cayenne.testdo.inheritance.vertical.IvSub2;
 import org.apache.cayenne.unit.AccessStack;
 import org.apache.cayenne.unit.CayenneCase;
 import org.apache.cayenne.unit.CayenneResources;
@@ -33,11 +41,130 @@ public class VerticalInheritanceTest ext
         return CayenneResources.getResources().getAccessStack("InheritanceVerticalStack");
     }
 
-    public void testSelectQuery() throws Exception {
+    public void testInsert_Root() throws Exception {
+        DBHelper dbHelper = getDbHelper();
+
+        TableHelper ivRootTable = new TableHelper(dbHelper, "IV_ROOT");
+        ivRootTable.setColumns("ID", "NAME", "DISCRIMINATOR");
+        ivRootTable.deleteAll();
+
+        assertEquals(0, ivRootTable.getRowCount());
+
+        IvRoot root = createDataContext().newObject(IvRoot.class);
+        root.setName("XyZ");
+        root.getObjectContext().commitChanges();
+
+        assertEquals(1, ivRootTable.getRowCount());
+
+        Object[] rootData = ivRootTable.select();
+        assertEquals(3, rootData.length);
+        assertTrue(rootData[0] instanceof Number);
+        assertTrue(((Number) rootData[0]).intValue() > 0);
+        assertEquals("XyZ", rootData[1]);
+        assertNull(rootData[2]);
+    }
+
+    public void testInsert_Sub1() throws Exception {
+        DBHelper dbHelper = getDbHelper();
+
+        TableHelper ivRootTable = new TableHelper(dbHelper, "IV_ROOT");
+        ivRootTable.setColumns("ID", "NAME", "DISCRIMINATOR");
+
+        TableHelper ivSub1Table = new TableHelper(dbHelper, "IV_SUB1");
+        ivSub1Table.setColumns("ID", "SUB1_NAME");
+
+        ivSub1Table.deleteAll();
+        ivRootTable.deleteAll();
+
+        IvSub1 sub1 = createDataContext().newObject(IvSub1.class);
+        sub1.setName("XyZX");
+        sub1.getObjectContext().commitChanges();
+
+        assertEquals(1, ivRootTable.getRowCount());
+        assertEquals(1, ivSub1Table.getRowCount());
+
+        Object[] data = ivRootTable.select();
+        assertEquals(3, data.length);
+        assertTrue(data[0] instanceof Number);
+        assertTrue(((Number) data[0]).intValue() > 0);
+        assertEquals("XyZX", data[1]);
+        assertEquals("IvSub1", data[2]);
+
+        Object[] subdata = ivSub1Table.select();
+        assertEquals(2, subdata.length);
+        assertEquals(data[0], subdata[0]);
+        assertNull(subdata[1]);
+
+        ivSub1Table.deleteAll();
+        ivRootTable.deleteAll();
+
+        IvSub1 sub11 = createDataContext().newObject(IvSub1.class);
+        sub11.setName("XyZXY");
+        sub11.setSub1Name("BdE2");
+        sub11.getObjectContext().commitChanges();
+
+        data = ivRootTable.select();
+        assertEquals(3, data.length);
+        assertTrue(data[0] instanceof Number);
+        assertTrue(((Number) data[0]).intValue() > 0);
+        assertEquals("XyZXY", data[1]);
+        assertEquals("IvSub1", data[2]);
+
+        subdata = ivSub1Table.select();
+        assertEquals(2, subdata.length);
+        assertEquals(data[0], subdata[0]);
+        assertEquals("BdE2", subdata[1]);
+    }
+
+    public void testInsert_Sub1Sub1() throws Exception {
+        DBHelper dbHelper = getDbHelper();
+
+        TableHelper ivRootTable = new TableHelper(dbHelper, "IV_ROOT");
+        ivRootTable.setColumns("ID", "NAME", "DISCRIMINATOR");
+
+        TableHelper ivSub1Table = new TableHelper(dbHelper, "IV_SUB1");
+        ivSub1Table.setColumns("ID", "SUB1_NAME");
+
+        TableHelper ivSub1Sub1Table = new TableHelper(dbHelper, "IV_SUB1_SUB1");
+        ivSub1Sub1Table.setColumns("ID", "SUB1_SUB1_NAME");
+
+        ivSub1Sub1Table.deleteAll();
+        ivSub1Table.deleteAll();
+        ivRootTable.deleteAll();
+
+        IvSub1Sub1 sub1Sub1 = createDataContext().newObject(IvSub1Sub1.class);
+        sub1Sub1.setName("XyZN");
+        sub1Sub1.setSub1Name("mDA");
+        sub1Sub1.setSub1Sub1Name("3DQa");
+        sub1Sub1.getObjectContext().commitChanges();
+
+        assertEquals(1, ivRootTable.getRowCount());
+        assertEquals(1, ivSub1Table.getRowCount());
+        assertEquals(1, ivSub1Sub1Table.getRowCount());
+
+        Object[] data = ivRootTable.select();
+        assertEquals(3, data.length);
+        assertTrue(data[0] instanceof Number);
+        assertTrue(((Number) data[0]).intValue() > 0);
+        assertEquals("XyZN", data[1]);
+        assertEquals("IvSub1Sub1", data[2]);
+
+        Object[] subdata = ivSub1Table.select();
+        assertEquals(2, subdata.length);
+        assertEquals(data[0], subdata[0]);
+        assertEquals("mDA", subdata[1]);
+
+        Object[] subsubdata = ivSub1Sub1Table.select();
+        assertEquals(2, subsubdata.length);
+        assertEquals(data[0], subsubdata[0]);
+        assertEquals("3DQa", subsubdata[1]);
+    }
+
+    public void testSelectQuery_SuperSub() throws Exception {
         DBHelper dbHelper = getDbHelper();
 
         TableHelper ivRootTable = new TableHelper(dbHelper, "IV_ROOT");
-        ivRootTable.setColumns("ID", "NAME");
+        ivRootTable.setColumns("ID", "NAME", "DISCRIMINATOR");
 
         TableHelper ivSub1Table = new TableHelper(dbHelper, "IV_SUB1");
         ivSub1Table.setColumns("ID", "SUB1_NAME");
@@ -47,13 +174,234 @@ public class VerticalInheritanceTest ext
         ivRootTable.deleteAll();
 
         // insert
-        ivRootTable.insert(1, "xROOT");
-        ivRootTable.insert(2, "xSUB1_ROOT");
+        ivRootTable.insert(1, "xROOT", null);
+        ivRootTable.insert(2, "xSUB1_ROOT", "IvSub1");
         ivSub1Table.insert(2, "xSUB1");
 
         SelectQuery query = new SelectQuery(IvRoot.class);
-        // List<IvRoot> results = createDataContext().performQuery(query);
+        List<IvRoot> results = createDataContext().performQuery(query);
+
+        assertEquals(2, results.size());
+
+        // since we don't have ordering, need to analyze results in an order agnostic
+        // fashion
+        Map<String, IvRoot> resultTypes = new HashMap<String, IvRoot>();
+
+        for (IvRoot result : results) {
+            resultTypes.put(result.getClass().getName(), result);
+        }
+
+        assertEquals(2, resultTypes.size());
+
+        IvRoot root = resultTypes.get(IvRoot.class.getName());
+        assertNotNull(root);
+        assertEquals("xROOT", root.getName());
+        assertNull(root.getDiscriminator());
 
-        // assertEquals(2, results.size());
+        IvSub1 sub1 = (IvSub1) resultTypes.get(IvSub1.class.getName());
+        assertNotNull(sub1);
+        assertEquals("xSUB1_ROOT", sub1.getName());
+        assertEquals("IvSub1", sub1.getDiscriminator());
     }
+
+    public void testSelectQuery_DeepAndWide() throws Exception {
+        DBHelper dbHelper = getDbHelper();
+
+        TableHelper ivRootTable = new TableHelper(dbHelper, "IV_ROOT");
+        ivRootTable.setColumns("ID", "NAME", "DISCRIMINATOR");
+
+        TableHelper ivSub1Table = new TableHelper(dbHelper, "IV_SUB1");
+        ivSub1Table.setColumns("ID", "SUB1_NAME");
+
+        TableHelper ivSub2Table = new TableHelper(dbHelper, "IV_SUB2");
+        ivSub2Table.setColumns("ID", "SUB2_NAME");
+
+        TableHelper ivSub1Sub1Table = new TableHelper(dbHelper, "IV_SUB1_SUB1");
+        ivSub1Sub1Table.setColumns("ID", "SUB1_SUB1_NAME");
+
+        // delete
+        ivSub1Sub1Table.deleteAll();
+        ivSub2Table.deleteAll();
+        ivSub1Table.deleteAll();
+        ivRootTable.deleteAll();
+
+        // insert
+        ivRootTable.insert(1, "xROOT", null);
+
+        ivRootTable.insert(2, "xSUB1_ROOT", "IvSub1");
+        ivSub1Table.insert(2, "xSUB1");
+
+        ivRootTable.insert(3, "xSUB1_SUB1_ROOT", "IvSub1Sub1");
+        ivSub1Table.insert(3, "xSUB1_SUB1_SUBROOT");
+        ivSub1Sub1Table.insert(3, "xSUB1_SUB1");
+
+        ivRootTable.insert(4, "xROOT_SUB2", "IvSub2");
+        ivSub2Table.insert(4, "xSUB2");
+
+        SelectQuery query = new SelectQuery(IvRoot.class);
+        List<IvRoot> results = createDataContext().performQuery(query);
+
+        assertEquals(4, results.size());
+
+        // since we don't have ordering, need to analyze results in an order agnostic
+        // fashion
+        Map<String, IvRoot> resultTypes = new HashMap<String, IvRoot>();
+
+        for (IvRoot result : results) {
+            resultTypes.put(result.getClass().getName(), result);
+        }
+
+        assertEquals(4, resultTypes.size());
+
+        IvRoot root = resultTypes.get(IvRoot.class.getName());
+        assertNotNull(root);
+        assertEquals("xROOT", root.getName());
+        assertNull(root.getDiscriminator());
+
+        IvSub1 sub1 = (IvSub1) resultTypes.get(IvSub1.class.getName());
+        assertNotNull(sub1);
+        assertEquals("xSUB1_ROOT", sub1.getName());
+        assertEquals("IvSub1", sub1.getDiscriminator());
+
+        IvSub1Sub1 sub1Sub1 = (IvSub1Sub1) resultTypes.get(IvSub1Sub1.class.getName());
+        assertNotNull(sub1Sub1);
+        assertEquals("xSUB1_SUB1_ROOT", sub1Sub1.getName());
+        assertEquals("IvSub1Sub1", sub1Sub1.getDiscriminator());
+        assertEquals("xSUB1_SUB1_SUBROOT", sub1Sub1.getSub1Name());
+        assertEquals("xSUB1_SUB1", sub1Sub1.getSub1Sub1Name());
+
+        IvSub2 sub2 = (IvSub2) resultTypes.get(IvSub2.class.getName());
+        assertNotNull(sub2);
+        assertEquals("xROOT_SUB2", sub2.getName());
+        assertEquals("IvSub2", sub2.getDiscriminator());
+        assertEquals("xSUB2", sub2.getSub2Name());
+    }
+
+    public void testSelectQuery_MiddleLeaf() throws Exception {
+        DBHelper dbHelper = getDbHelper();
+
+        TableHelper ivRootTable = new TableHelper(dbHelper, "IV_ROOT");
+        ivRootTable.setColumns("ID", "NAME", "DISCRIMINATOR");
+
+        TableHelper ivSub1Table = new TableHelper(dbHelper, "IV_SUB1");
+        ivSub1Table.setColumns("ID", "SUB1_NAME");
+
+        TableHelper ivSub2Table = new TableHelper(dbHelper, "IV_SUB2");
+        ivSub2Table.setColumns("ID", "SUB2_NAME");
+
+        TableHelper ivSub1Sub1Table = new TableHelper(dbHelper, "IV_SUB1_SUB1");
+        ivSub1Sub1Table.setColumns("ID", "SUB1_SUB1_NAME");
+
+        // delete
+        ivSub1Sub1Table.deleteAll();
+        ivSub2Table.deleteAll();
+        ivSub1Table.deleteAll();
+        ivRootTable.deleteAll();
+
+        // insert
+        ivRootTable.insert(1, "xROOT", null);
+
+        ivRootTable.insert(2, "xSUB1_ROOT", "IvSub1");
+        ivSub1Table.insert(2, "xSUB1");
+
+        ivRootTable.insert(3, "xSUB1_SUB1_ROOT", "IvSub1Sub1");
+        ivSub1Table.insert(3, "xSUB1_SUB1_SUBROOT");
+        ivSub1Sub1Table.insert(3, "xSUB1_SUB1");
+
+        ivRootTable.insert(4, "xROOT_SUB2", "IvSub2");
+        ivSub2Table.insert(4, "xSUB2");
+
+        SelectQuery query = new SelectQuery(IvSub1.class);
+        List<IvRoot> results = createDataContext().performQuery(query);
+
+        assertEquals(2, results.size());
+
+        // since we don't have ordering, need to analyze results in an order agnostic
+        // fashion
+        Map<String, IvRoot> resultTypes = new HashMap<String, IvRoot>();
+
+        for (IvRoot result : results) {
+            resultTypes.put(result.getClass().getName(), result);
+        }
+
+        assertEquals(2, resultTypes.size());
+
+        IvSub1 sub1 = (IvSub1) resultTypes.get(IvSub1.class.getName());
+        assertNotNull(sub1);
+        assertEquals("xSUB1_ROOT", sub1.getName());
+        assertEquals("IvSub1", sub1.getDiscriminator());
+
+        IvSub1Sub1 sub1Sub1 = (IvSub1Sub1) resultTypes.get(IvSub1Sub1.class.getName());
+        assertNotNull(sub1Sub1);
+        assertEquals("xSUB1_SUB1_ROOT", sub1Sub1.getName());
+        assertEquals("IvSub1Sub1", sub1Sub1.getDiscriminator());
+        assertEquals("xSUB1_SUB1_SUBROOT", sub1Sub1.getSub1Name());
+        assertEquals("xSUB1_SUB1", sub1Sub1.getSub1Sub1Name());
+    }
+
+    public void testDelete_Mix() throws Exception {
+        DBHelper dbHelper = getDbHelper();
+
+        TableHelper ivRootTable = new TableHelper(dbHelper, "IV_ROOT");
+        ivRootTable.setColumns("ID", "NAME", "DISCRIMINATOR");
+
+        TableHelper ivSub1Table = new TableHelper(dbHelper, "IV_SUB1");
+        ivSub1Table.setColumns("ID", "SUB1_NAME");
+
+        TableHelper ivSub2Table = new TableHelper(dbHelper, "IV_SUB2");
+        ivSub2Table.setColumns("ID", "SUB2_NAME");
+
+        TableHelper ivSub1Sub1Table = new TableHelper(dbHelper, "IV_SUB1_SUB1");
+        ivSub1Sub1Table.setColumns("ID", "SUB1_SUB1_NAME");
+
+        // delete
+        ivSub1Sub1Table.deleteAll();
+        ivSub2Table.deleteAll();
+        ivSub1Table.deleteAll();
+        ivRootTable.deleteAll();
+
+        // insert
+        ivRootTable.insert(1, "xROOT", null);
+
+        ivRootTable.insert(2, "xSUB1_ROOT", "IvSub1");
+        ivSub1Table.insert(2, "xSUB1");
+
+        ivRootTable.insert(3, "xSUB1_SUB1_ROOT", "IvSub1Sub1");
+        ivSub1Table.insert(3, "xSUB1_SUB1_SUBROOT");
+        ivSub1Sub1Table.insert(3, "xSUB1_SUB1");
+
+        ivRootTable.insert(4, "xROOT_SUB2", "IvSub2");
+        ivSub2Table.insert(4, "xSUB2");
+
+        SelectQuery query = new SelectQuery(IvRoot.class);
+
+        ObjectContext context = createDataContext();
+        List<IvRoot> results = context.performQuery(query);
+
+        assertEquals(4, results.size());
+        Map<String, IvRoot> resultTypes = new HashMap<String, IvRoot>();
+
+        for (IvRoot result : results) {
+            resultTypes.put(result.getClass().getName(), result);
+        }
+
+        assertEquals(4, resultTypes.size());
+
+        IvRoot root = resultTypes.get(IvRoot.class.getName());
+        context.deleteObject(root);
+
+        IvSub1 sub1 = (IvSub1) resultTypes.get(IvSub1.class.getName());
+        context.deleteObject(sub1);
+
+        context.commitChanges();
+
+        assertEquals(2, ivRootTable.getRowCount());
+        assertEquals(1, ivSub1Table.getRowCount());
+        assertEquals(1, ivSub1Sub1Table.getRowCount());
+        assertEquals(1, ivSub2Table.getRowCount());
+
+        results = context.performQuery(query);
+        assertEquals(2, results.size());
+    }
+
 }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/inheritance/vertical/auto/_IvRoot.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/inheritance/vertical/auto/_IvRoot.java?rev=951630&r1=951629&r2=951630&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/inheritance/vertical/auto/_IvRoot.java (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/java/org/apache/cayenne/testdo/inheritance/vertical/auto/_IvRoot.java Sat Jun  5 01:09:43 2010
@@ -10,10 +10,18 @@ import org.apache.cayenne.CayenneDataObj
  */
 public abstract class _IvRoot extends CayenneDataObject {
 
+    public static final String DISCRIMINATOR_PROPERTY = "discriminator";
     public static final String NAME_PROPERTY = "name";
 
     public static final String ID_PK_COLUMN = "ID";
 
+    public void setDiscriminator(String discriminator) {
+        writeProperty("discriminator", discriminator);
+    }
+    public String getDiscriminator() {
+        return (String)readProperty("discriminator");
+    }
+
     public void setName(String name) {
         writeProperty("name", name);
     }

Modified: cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/inheritance-vertical.map.xml
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/inheritance-vertical.map.xml?rev=951630&r1=951629&r2=951630&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/inheritance-vertical.map.xml (original)
+++ cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/test/resources/inheritance-vertical.map.xml Sat Jun  5 01:09:43 2010
@@ -5,6 +5,7 @@
 	 project-version="6">
 	<property name="defaultPackage" value="org.apache.cayenne.testdo.inheritance.vertical"/>
 	<db-entity name="IV_ROOT">
+		<db-attribute name="DISCRIMINATOR" type="VARCHAR" length="10"/>
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 		<db-attribute name="NAME" type="VARCHAR" length="100"/>
 	</db-entity>
@@ -22,16 +23,23 @@
 		<db-attribute name="SUB2_NAME" type="VARCHAR" length="100"/>
 	</db-entity>
 	<obj-entity name="IvRoot" className="org.apache.cayenne.testdo.inheritance.vertical.IvRoot" dbEntityName="IV_ROOT">
+		<obj-attribute name="discriminator" type="java.lang.String" db-attribute-path="DISCRIMINATOR"/>
 		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
 	</obj-entity>
-	<obj-entity name="IvSub1" superEntityName="IvRoot" className="org.apache.cayenne.testdo.inheritance.vertical.IvSub1" dbEntityName="IV_SUB1">
-		<obj-attribute name="sub1Name" type="java.lang.String" db-attribute-path="SUB1_NAME"/>
+	<obj-entity name="IvSub1" superEntityName="IvRoot" className="org.apache.cayenne.testdo.inheritance.vertical.IvSub1" dbEntityName="IV_ROOT">
+		<qualifier><![CDATA[discriminator = "IvSub1"]]></qualifier>
+		<obj-attribute name="sub1Name" type="java.lang.String" db-attribute-path="sub1.SUB1_NAME"/>
+		<attribute-override name="discrimiantor" db-attribute-path="DISCRIMINATOR"/>
+		<attribute-override name="discriminator" db-attribute-path="DISCRIMINATOR"/>
+		<attribute-override name="name" db-attribute-path="NAME"/>
 	</obj-entity>
-	<obj-entity name="IvSub1Sub1" superEntityName="IvSub1" className="org.apache.cayenne.testdo.inheritance.vertical.IvSub1Sub1" dbEntityName="IV_SUB1_SUB1">
-		<obj-attribute name="sub1Sub1Name" type="java.lang.String" db-attribute-path="SUB1_SUB1_NAME"/>
+	<obj-entity name="IvSub1Sub1" superEntityName="IvSub1" className="org.apache.cayenne.testdo.inheritance.vertical.IvSub1Sub1" dbEntityName="IV_ROOT">
+		<qualifier><![CDATA[discriminator = "IvSub1Sub1"]]></qualifier>
+		<obj-attribute name="sub1Sub1Name" type="java.lang.String" db-attribute-path="sub1.sub1Sub1.SUB1_SUB1_NAME"/>
 	</obj-entity>
-	<obj-entity name="IvSub2" superEntityName="IvRoot" className="org.apache.cayenne.testdo.inheritance.vertical.IvSub2" dbEntityName="IV_SUB2">
-		<obj-attribute name="sub2Name" type="java.lang.String" db-attribute-path="SUB2_NAME"/>
+	<obj-entity name="IvSub2" superEntityName="IvRoot" className="org.apache.cayenne.testdo.inheritance.vertical.IvSub2" dbEntityName="IV_ROOT">
+		<qualifier><![CDATA[discriminator = "IvSub2"]]></qualifier>
+		<obj-attribute name="sub2Name" type="java.lang.String" db-attribute-path="sub2.SUB2_NAME"/>
 	</obj-entity>
 	<db-relationship name="sub1" source="IV_ROOT" target="IV_SUB1" toDependentPK="true" toMany="false">
 		<db-attribute-pair source="ID" target="ID"/>