You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2021/03/26 14:54:44 UTC

[cayenne] branch master updated: CAY-2704 Vertical inheritance with Embeddedables looses ObjAttribute information

This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/master by this push:
     new 16d61ac  CAY-2704 Vertical inheritance with Embeddedables looses ObjAttribute information
16d61ac is described below

commit 16d61acf01fefd2e1a6f2d31440c10863406510f
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Fri Mar 26 17:54:35 2021 +0300

    CAY-2704 Vertical inheritance with Embeddedables looses ObjAttribute information
---
 .../org/apache/cayenne/map/EmbeddedAttribute.java  | 24 ++++--
 .../java/org/apache/cayenne/map/ObjEntity.java     | 27 +++++--
 .../org/apache/cayenne/access/EmbeddingIT.java     | 62 +++++++++++++++
 .../cayenne/testdo/embeddable/EmbedChild.java      |  9 +++
 .../cayenne/testdo/embeddable/EmbedRoot.java       |  9 +++
 .../testdo/embeddable/auto/_EmbedChild.java        | 87 ++++++++++++++++++++++
 .../testdo/embeddable/auto/_EmbedEntity1.java      |  2 +-
 .../testdo/embeddable/auto/_EmbedEntity2.java      |  2 +-
 .../auto/{_EmbedEntity2.java => _EmbedRoot.java}   | 35 ++++-----
 .../src/test/resources/embeddable.map.xml          | 27 +++++++
 10 files changed, 252 insertions(+), 32 deletions(-)

diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/EmbeddedAttribute.java b/cayenne-server/src/main/java/org/apache/cayenne/map/EmbeddedAttribute.java
index a3d99ef..6acad57 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/EmbeddedAttribute.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/EmbeddedAttribute.java
@@ -54,6 +54,21 @@ public class EmbeddedAttribute extends ObjAttribute {
         setEntity(entity);
     }
 
+    /**
+     * Copying constructor
+     * @param other attribute to copy
+     * @since 4.2
+     */
+    public EmbeddedAttribute(EmbeddedAttribute other) {
+        setName(other.getName());
+        setType(other.getType());
+        setEntity(other.getEntity());
+        setDbAttributePath(other.getDbAttributePath());
+        setUsedForLocking(other.isUsedForLocking());
+        setLazy(other.isLazy());
+        attributeOverrides = other.getAttributeOverrides();
+    }
+
     @Override
     public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) {
         encoder.start("embedded-attribute")
@@ -91,15 +106,10 @@ public class EmbeddedAttribute extends ObjAttribute {
         return makeObjAttribute(embeddableAttribute, dbPath);
     }
 
-    private ObjAttribute makeObjAttribute(
-            EmbeddableAttribute embeddableAttribute,
-            String dbPath) {
+    private ObjAttribute makeObjAttribute(EmbeddableAttribute embeddableAttribute, String dbPath) {
         String fullName = getName() + "." + embeddableAttribute.getName();
 
-        ObjAttribute oa = new ObjAttribute(
-                fullName,
-                embeddableAttribute.getType(),
-                (ObjEntity) getEntity());
+        ObjAttribute oa = new ObjAttribute(fullName, embeddableAttribute.getType(), getEntity());
         oa.setDbAttributePath(dbPath);
         return oa;
     }
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java
index 47ea965..a59065c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/ObjEntity.java
@@ -32,6 +32,8 @@ import org.apache.cayenne.map.event.ObjEntityListener;
 import org.apache.cayenne.util.CayenneMapEntry;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.util.XMLEncoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -52,11 +54,12 @@ import java.util.function.Function;
  */
 public class ObjEntity extends Entity implements ObjEntityListener, ConfigurationNode {
 
+    private static final Logger LOGGER = LoggerFactory.getLogger(ObjEntity.class);
+
     public static final int LOCK_TYPE_NONE = 0;
     public static final int LOCK_TYPE_OPTIMISTIC = 1;
 
-    // do not import CayenneDataObject as it introduces unneeded client
-    // dependency
+    // do not import CayenneDataObject as it introduces unneeded client dependency
     private static final String CAYENNE_DATA_OBJECT_CLASS = "org.apache.cayenne.CayenneDataObject";
     /**
      * A collection of default "generic" entity classes excluded from class
@@ -641,11 +644,23 @@ public class ObjEntity extends Entity implements ObjEntityListener, Configuratio
 
                 String overridedDbPath = attributeOverrides.get(attributeName);
 
-                ObjAttribute attribute = new ObjAttribute(attributeMap.get(attributeName));
-                attribute.setEntity(this);
-                if (overridedDbPath != null) {
-                    attribute.setDbAttributePath(overridedDbPath);
+                ObjAttribute superAttribute = attributeMap.get(attributeName);
+                ObjAttribute attribute;
+
+                if(superAttribute instanceof EmbeddedAttribute) {
+                    EmbeddedAttribute embeddedAttribute = new EmbeddedAttribute((EmbeddedAttribute)superAttribute);
+                    if(overridedDbPath != null) {
+                        LOGGER.warn("'{}.{}': DB path override for an embedded attribute is not supported.",
+                                getName(), attributeName);
+                    }
+                    attribute = embeddedAttribute;
+                } else {
+                    attribute = new ObjAttribute(superAttribute);
+                    if (overridedDbPath != null) {
+                        attribute.setDbAttributePath(overridedDbPath);
+                    }
                 }
+                attribute.setEntity(this);
                 map.put(attributeName, attribute);
             }
         }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
index 0f3f291..c01f363 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
@@ -25,8 +25,10 @@ import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.embeddable.EmbedChild;
 import org.apache.cayenne.testdo.embeddable.EmbedEntity1;
 import org.apache.cayenne.testdo.embeddable.EmbedEntity2;
+import org.apache.cayenne.testdo.embeddable.EmbedRoot;
 import org.apache.cayenne.testdo.embeddable.Embeddable1;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
@@ -38,6 +40,7 @@ import java.util.List;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 @UseServerRuntime(CayenneProjects.EMBEDDABLE_PROJECT)
 public class EmbeddingIT extends ServerCase {
@@ -50,6 +53,8 @@ public class EmbeddingIT extends ServerCase {
     
     protected TableHelper tEmbedEntity1;
     protected TableHelper tEmbedEntity2;
+    protected TableHelper tEmbedRoot;
+    protected TableHelper tEmbedChild;
 
     @Before
     public void setUp() throws Exception {
@@ -58,6 +63,12 @@ public class EmbeddingIT extends ServerCase {
 
         tEmbedEntity2 = new TableHelper(dbHelper, "EMBED_ENTITY2");
         tEmbedEntity2.setColumns("ID", "NAME", "ENTITY1_ID", "EMBEDDED10", "EMBEDDED20");
+
+        tEmbedRoot = new TableHelper(dbHelper, "EMBED_ROOT");
+        tEmbedRoot.setColumns("ID", "NAME", "EMBEDDED10", "EMBEDDED20", "TYPE");
+
+        tEmbedChild = new TableHelper(dbHelper, "EMBED_CHILD");
+        tEmbedChild.setColumns("ID", "CHILD_ATTR");
     }
     
     protected void createSelectDataSet() throws Exception {
@@ -71,6 +82,12 @@ public class EmbeddingIT extends ServerCase {
         tEmbedEntity2.insert(2, "n2-1", 2, "e1", "e2");
     }
 
+    protected void createSelectDataSetInheritance() throws Exception {
+        tEmbedRoot.insert(1, "root1", "e1-1", "e2-1", 0);
+        tEmbedRoot.insert(2, "root2", "e1-2", "e2-2", 1);
+        tEmbedChild.insert(2, "child-attr1");
+    }
+
     protected void createUpdateDataSet() throws Exception {
         tEmbedEntity1.insert(1, "n1", "e1", "e2", "e3", "e4");
     }
@@ -298,4 +315,49 @@ public class EmbeddingIT extends ServerCase {
                 .select(context);
         assertEquals(1, result.size());
     }
+
+    @Test
+    public void testSelectWithInheritance() throws Exception {
+        createSelectDataSetInheritance();
+
+        List<EmbedRoot> roots = ObjectSelect.query(EmbedRoot.class)
+                .orderBy(EmbedRoot.NAME.asc())
+                .select(context);
+
+        assertEquals(2, roots.size());
+
+        EmbedRoot root = roots.get(0);
+        EmbedRoot child = roots.get(1);
+        assertTrue(child instanceof EmbedChild);
+
+        assertEquals("e1-1", root.getEmbedded().getEmbedded10());
+        assertEquals("e2-1", root.getEmbedded().getEmbedded20());
+
+        assertEquals("e1-2", child.getEmbedded().getEmbedded10());
+        assertEquals("e2-2", child.getEmbedded().getEmbedded20());
+        assertEquals("child-attr1", ((EmbedChild) child).getChildAttr());
+    }
+
+    @Test
+    public void testInsertWithInheritance() {
+        {
+            EmbedRoot root = context.newObject(EmbedRoot.class);
+            root.setName("root");
+            Embeddable1 embeddable1 = new Embeddable1();
+            embeddable1.setEmbedded10("root-10");
+            embeddable1.setEmbedded20("root-20");
+            root.setEmbedded(embeddable1);
+        }
+
+        {
+            EmbedChild child = context.newObject(EmbedChild.class);
+            child.setName("child");
+            Embeddable1 embeddable1 = new Embeddable1();
+            embeddable1.setEmbedded10("child-10");
+            embeddable1.setEmbedded20("child-20");
+            child.setEmbedded(embeddable1);
+        }
+
+        context.commitChanges();
+    }
 }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/EmbedChild.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/EmbedChild.java
new file mode 100644
index 0000000..f90058f
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/EmbedChild.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.testdo.embeddable;
+
+import org.apache.cayenne.testdo.embeddable.auto._EmbedChild;
+
+public class EmbedChild extends _EmbedChild {
+
+    private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/EmbedRoot.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/EmbedRoot.java
new file mode 100644
index 0000000..a7c5dd3
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/EmbedRoot.java
@@ -0,0 +1,9 @@
+package org.apache.cayenne.testdo.embeddable;
+
+import org.apache.cayenne.testdo.embeddable.auto._EmbedRoot;
+
+public class EmbedRoot extends _EmbedRoot {
+
+    private static final long serialVersionUID = 1L;
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedChild.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedChild.java
new file mode 100644
index 0000000..a43726a
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedChild.java
@@ -0,0 +1,87 @@
+package org.apache.cayenne.testdo.embeddable.auto;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.embeddable.EmbedRoot;
+
+/**
+ * Class _EmbedChild was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _EmbedChild extends EmbedRoot {
+
+    private static final long serialVersionUID = 1L;
+
+    public static final String ID_PK_COLUMN = "ID";
+
+    public static final StringProperty<String> CHILD_ATTR = PropertyFactory.createString("childAttr", String.class);
+
+    protected String childAttr;
+
+
+    public void setChildAttr(String childAttr) {
+        beforePropertyWrite("childAttr", this.childAttr, childAttr);
+        this.childAttr = childAttr;
+    }
+
+    public String getChildAttr() {
+        beforePropertyRead("childAttr");
+        return this.childAttr;
+    }
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "childAttr":
+                return this.childAttr;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "childAttr":
+                this.childAttr = (String)val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.childAttr);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.childAttr = (String)in.readObject();
+    }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java
index e5d29cb..82b8a1d 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity1.java
@@ -21,7 +21,7 @@ import org.apache.cayenne.testdo.embeddable.Embeddable1;
  */
 public abstract class _EmbedEntity1 extends BaseDataObject {
 
-    private static final long serialVersionUID = 1L; 
+    private static final long serialVersionUID = 1L;
 
     public static final String ID_PK_COLUMN = "ID";
 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java
index 5d867b2..c4875eb 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java
@@ -20,7 +20,7 @@ import org.apache.cayenne.testdo.embeddable.Embeddable1;
  */
 public abstract class _EmbedEntity2 extends BaseDataObject {
 
-    private static final long serialVersionUID = 1L; 
+    private static final long serialVersionUID = 1L;
 
     public static final String ID_PK_COLUMN = "ID";
 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedRoot.java
similarity index 78%
copy from cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java
copy to cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedRoot.java
index 5d867b2..0d12bae 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedEntity2.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/embeddable/auto/_EmbedRoot.java
@@ -6,32 +6,31 @@ import java.io.ObjectOutputStream;
 
 import org.apache.cayenne.BaseDataObject;
 import org.apache.cayenne.exp.property.EmbeddableProperty;
-import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.NumericProperty;
 import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.exp.property.StringProperty;
-import org.apache.cayenne.testdo.embeddable.EmbedEntity1;
 import org.apache.cayenne.testdo.embeddable.Embeddable1;
 
 /**
- * Class _EmbedEntity2 was generated by Cayenne.
+ * Class _EmbedRoot was generated by Cayenne.
  * It is probably a good idea to avoid changing this class manually,
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _EmbedEntity2 extends BaseDataObject {
+public abstract class _EmbedRoot extends BaseDataObject {
 
-    private static final long serialVersionUID = 1L; 
+    private static final long serialVersionUID = 1L;
 
     public static final String ID_PK_COLUMN = "ID";
 
     public static final EmbeddableProperty<Embeddable1> EMBEDDED = PropertyFactory.createEmbeddable("embedded", Embeddable1.class);
     public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
-    public static final EntityProperty<EmbedEntity1> ENTITY1 = PropertyFactory.createEntity("entity1", EmbedEntity1.class);
+    public static final NumericProperty<Integer> TYPE = PropertyFactory.createNumeric("type", Integer.class);
 
     protected Embeddable1 embedded;
     protected String name;
+    protected int type;
 
-    protected Object entity1;
 
     public void setEmbedded(Embeddable1 embedded) {
         beforePropertyWrite("embedded", this.embedded, embedded);
@@ -53,12 +52,14 @@ public abstract class _EmbedEntity2 extends BaseDataObject {
         return this.name;
     }
 
-    public void setEntity1(EmbedEntity1 entity1) {
-        setToOneTarget("entity1", entity1, true);
+    public void setType(int type) {
+        beforePropertyWrite("type", this.type, type);
+        this.type = type;
     }
 
-    public EmbedEntity1 getEntity1() {
-        return (EmbedEntity1)readProperty("entity1");
+    public int getType() {
+        beforePropertyRead("type");
+        return this.type;
     }
 
     @Override
@@ -72,8 +73,8 @@ public abstract class _EmbedEntity2 extends BaseDataObject {
                 return this.embedded;
             case "name":
                 return this.name;
-            case "entity1":
-                return this.entity1;
+            case "type":
+                return this.type;
             default:
                 return super.readPropertyDirectly(propName);
         }
@@ -92,8 +93,8 @@ public abstract class _EmbedEntity2 extends BaseDataObject {
             case "name":
                 this.name = (String)val;
                 break;
-            case "entity1":
-                this.entity1 = val;
+            case "type":
+                this.type = val == null ? 0 : (int)val;
                 break;
             default:
                 super.writePropertyDirectly(propName, val);
@@ -113,7 +114,7 @@ public abstract class _EmbedEntity2 extends BaseDataObject {
         super.writeState(out);
         out.writeObject(this.embedded);
         out.writeObject(this.name);
-        out.writeObject(this.entity1);
+        out.writeInt(this.type);
     }
 
     @Override
@@ -121,7 +122,7 @@ public abstract class _EmbedEntity2 extends BaseDataObject {
         super.readState(in);
         this.embedded = (Embeddable1)in.readObject();
         this.name = (String)in.readObject();
-        this.entity1 = in.readObject();
+        this.type = in.readInt();
     }
 
 }
diff --git a/cayenne-server/src/test/resources/embeddable.map.xml b/cayenne-server/src/test/resources/embeddable.map.xml
index dbcae05..c01ed73 100644
--- a/cayenne-server/src/test/resources/embeddable.map.xml
+++ b/cayenne-server/src/test/resources/embeddable.map.xml
@@ -8,6 +8,10 @@
 		<embeddable-attribute name="embedded20" type="java.lang.String" db-attribute-name="EMBEDDED20"/>
 		<embeddable-attribute name="embedded10" type="java.lang.String" db-attribute-name="EMBEDDED10"/>
 	</embeddable>
+	<db-entity name="EMBED_CHILD">
+		<db-attribute name="CHILD_ATTR" type="VARCHAR" length="100"/>
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+	</db-entity>
 	<db-entity name="EMBED_ENTITY1">
 		<db-attribute name="EMBEDDED10" type="VARCHAR" length="100"/>
 		<db-attribute name="EMBEDDED20" type="VARCHAR" length="100"/>
@@ -23,6 +27,17 @@
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 		<db-attribute name="NAME" type="VARCHAR" length="100"/>
 	</db-entity>
+	<db-entity name="EMBED_ROOT">
+		<db-attribute name="EMBEDDED10" type="VARCHAR" length="100"/>
+		<db-attribute name="EMBEDDED20" type="VARCHAR" length="100"/>
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="NAME" type="VARCHAR" isMandatory="true" length="100"/>
+		<db-attribute name="TYPE" type="INTEGER" isMandatory="true"/>
+	</db-entity>
+	<obj-entity name="EmbedChild" superEntityName="EmbedRoot" className="org.apache.cayenne.testdo.embeddable.EmbedChild">
+		<qualifier><![CDATA[type = 1]]></qualifier>
+		<obj-attribute name="childAttr" type="java.lang.String" db-attribute-path="child.CHILD_ATTR"/>
+	</obj-entity>
 	<obj-entity name="EmbedEntity1" className="org.apache.cayenne.testdo.embeddable.EmbedEntity1" dbEntityName="EMBED_ENTITY1">
 		<embedded-attribute name="embedded1" type="org.apache.cayenne.testdo.embeddable.Embeddable1"/>
 		<embedded-attribute name="embedded2" type="org.apache.cayenne.testdo.embeddable.Embeddable1">
@@ -35,12 +50,24 @@
 		<embedded-attribute name="embedded" type="org.apache.cayenne.testdo.embeddable.Embeddable1"/>
 		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
 	</obj-entity>
+	<obj-entity name="EmbedRoot" className="org.apache.cayenne.testdo.embeddable.EmbedRoot" dbEntityName="EMBED_ROOT">
+		<qualifier><![CDATA[type = 0]]></qualifier>
+		<embedded-attribute name="embedded" type="org.apache.cayenne.testdo.embeddable.Embeddable1"/>
+		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
+		<obj-attribute name="type" type="int" db-attribute-path="TYPE"/>
+	</obj-entity>
+	<db-relationship name="root" source="EMBED_CHILD" target="EMBED_ROOT">
+		<db-attribute-pair source="ID" target="ID"/>
+	</db-relationship>
 	<db-relationship name="untitledRel" source="EMBED_ENTITY1" target="EMBED_ENTITY2" toMany="true">
 		<db-attribute-pair source="ID" target="ENTITY1_ID"/>
 	</db-relationship>
 	<db-relationship name="untitledRel" source="EMBED_ENTITY2" target="EMBED_ENTITY1">
 		<db-attribute-pair source="ENTITY1_ID" target="ID"/>
 	</db-relationship>
+	<db-relationship name="child" source="EMBED_ROOT" target="EMBED_CHILD" toDependentPK="true">
+		<db-attribute-pair source="ID" target="ID"/>
+	</db-relationship>
 	<obj-relationship name="embedEntity2s" source="EmbedEntity1" target="EmbedEntity2" deleteRule="Deny" db-relationship-path="untitledRel"/>
 	<obj-relationship name="entity1" source="EmbedEntity2" target="EmbedEntity1" deleteRule="Nullify" db-relationship-path="untitledRel"/>
 </data-map>