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 2020/04/03 08:52:03 UTC

[cayenne] branch master updated: CAY-2652 New flush action: unable to use meaningful FK mapped to primitive type

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 a04c024  CAY-2652 New flush action: unable to use meaningful FK mapped to primitive type
     new c946c19  Merge branch 'pull/416' into asf-master
a04c024 is described below

commit a04c024164efd649bd821ee7344ad0bcd92a3516
Author: Nikita Timofeev <st...@gmail.com>
AuthorDate: Wed Apr 1 11:52:35 2020 +0300

    CAY-2652 New flush action: unable to use meaningful FK mapped to primitive type
---
 .../access/flush/ArcValuesCreationHandler.java     |   4 +-
 .../access/flush/ValuesCreationHandler.java        |   2 +-
 .../cayenne/access/flush/operation/Values.java     | 100 ++++++++++++++-------
 .../java/org/apache/cayenne/MeaningfulFKIT.java    |  21 +++--
 .../access/flush/operation/DbRowOpMergerTest.java  |   8 +-
 .../cayenne/access/flush/operation/ValuesTest.java |   2 +-
 .../relationships/auto/_FkOfDifferentType.java     |   3 -
 .../testdo/relationships/auto/_MeaningfulFK.java   |  14 ++-
 .../relationships/auto/_ReflexiveAndToOne.java     |   3 -
 .../relationships/auto/_RelationshipHelper.java    |   3 -
 .../src/test/resources/cayenne-relationships.xml   |   2 +
 .../src/test/resources/relationships.map.xml       |  17 +++-
 12 files changed, 117 insertions(+), 62 deletions(-)

diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
index 86520d9..91f86bd 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
@@ -254,13 +254,13 @@ class ArcValuesCreationHandler implements GraphChangeHandler {
 
         @Override
         public Void visitInsert(InsertDbRowOp dbRow) {
-            dbRow.getValues().addValue(attribute, add ? valueToUse : null);
+            dbRow.getValues().addValue(attribute, add ? valueToUse : null, true);
             return null;
         }
 
         @Override
         public Void visitUpdate(UpdateDbRowOp dbRow) {
-            dbRow.getValues().addValue(attribute, add ? valueToUse : null);
+            dbRow.getValues().addValue(attribute, add ? valueToUse : null, true);
             return null;
         }
 
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ValuesCreationHandler.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ValuesCreationHandler.java
index bbf2105..defdb1a 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ValuesCreationHandler.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ValuesCreationHandler.java
@@ -70,7 +70,7 @@ class ValuesCreationHandler extends ArcValuesCreationHandler {
 
         DbRowOpWithValues dbRow = factory.get(id);
         if(dbRow != null) {
-            dbRow.getValues().addValue(dbAttribute, newValue);
+            dbRow.getValues().addValue(dbAttribute, newValue, false);
         }
     }
 
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Values.java b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Values.java
index 91b8e93..f893b09 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Values.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/operation/Values.java
@@ -38,7 +38,9 @@ public class Values {
     protected final DbRowOp row;
     protected final boolean includeId;
     // new values to store to DB
-    protected Map<String, Object> snapshot;
+    protected Map<String, Object> attributeSnapshot;
+    protected Map<String, Object> fkSnapshot;
+
     protected List<DbAttribute> updatedAttributes;
     // generated flattened Ids for this insert
     protected Map<String, ObjectId> flattenedIds;
@@ -48,28 +50,52 @@ public class Values {
         this.includeId = includeId;
     }
 
-    public void addValue(DbAttribute attribute, Object value) {
-        if(snapshot == null) {
-            snapshot = new HashMap<>();
+    public void addValue(DbAttribute attribute, Object value, boolean fk) {
+        if(fk) {
+            if (fkSnapshot == null) {
+                fkSnapshot = new HashMap<>();
+            }
+            fkSnapshot.put(attribute.getName(), value);
+        } else {
+            if (attributeSnapshot == null) {
+                attributeSnapshot = new HashMap<>();
+            }
+            attributeSnapshot.put(attribute.getName(), value);
+        }
+
+        if(updatedAttributes == null) {
             updatedAttributes = new ArrayList<>();
         }
-        snapshot.put(attribute.getName(), value);
         if(!updatedAttributes.contains(attribute)) {
             updatedAttributes.add(attribute);
         }
     }
 
     public void merge(Values other) {
-        if(this.snapshot == null) {
-            this.snapshot = other.snapshot;
+        if(this.updatedAttributes == null || updatedAttributes.isEmpty()) {
+            this.attributeSnapshot = other.attributeSnapshot;
+            this.fkSnapshot = other.fkSnapshot;
             this.updatedAttributes = other.updatedAttributes;
-        } else if(other.snapshot != null) {
-            other.snapshot.forEach(snapshot::putIfAbsent);
-            other.updatedAttributes.forEach(attr -> {
-                if(!updatedAttributes.contains(attr)) {
-                    updatedAttributes.add(attr);
+        } else {
+            if(other.attributeSnapshot != null) {
+                if(this.attributeSnapshot == null) {
+                    this.attributeSnapshot = new HashMap<>(other.attributeSnapshot.size());
+                }
+                other.attributeSnapshot.forEach(attributeSnapshot::putIfAbsent);
+            }
+            if(other.fkSnapshot != null) {
+                if(this.fkSnapshot == null) {
+                    this.fkSnapshot = new HashMap<>(other.fkSnapshot.size());
                 }
-            });
+                other.fkSnapshot.forEach(fkSnapshot::putIfAbsent);
+            }
+            if(other.updatedAttributes != null) {
+                other.updatedAttributes.forEach(attr -> {
+                    if (!updatedAttributes.contains(attr)) {
+                        updatedAttributes.add(attr);
+                    }
+                });
+            }
         }
 
         if(other.flattenedIds != null) {
@@ -99,19 +125,29 @@ public class Values {
 
     public Map<String, Object> getSnapshot() {
         if(!includeId) {
-            if(snapshot == null) {
-                return Collections.emptyMap();
-            }
-            return snapshot;
+            return mergeSnapshots();
         } else {
-            if (snapshot == null) {
-                snapshot = new HashMap<>();
-                snapshot.putAll(row.getChangeId().getIdSnapshot());
-                return snapshot;
+            Map<String, Object> mergedSnapshot = mergeSnapshots();
+            if(mergedSnapshot.isEmpty()) {
+                return new HashMap<>(row.getChangeId().getIdSnapshot());
             }
-            snapshot.putAll(row.getChangeId().getIdSnapshot());
-            return snapshot;
+            mergedSnapshot.putAll(row.getChangeId().getIdSnapshot());
+            return mergedSnapshot;
+        }
+    }
+
+    private Map<String, Object> mergeSnapshots() {
+        if(attributeSnapshot == null && fkSnapshot == null) {
+            return Collections.emptyMap();
+        }
+        if(attributeSnapshot == null) {
+            return fkSnapshot;
+        } else if(fkSnapshot == null) {
+            return attributeSnapshot;
         }
+        // FK should override attribute values
+        fkSnapshot.forEach(attributeSnapshot::put);
+        return attributeSnapshot;
     }
 
     public List<DbAttribute> getUpdatedAttributes() {
@@ -132,12 +168,16 @@ public class Values {
         if(includeId) {
             return false;
         }
-        return snapshot == null || snapshot.isEmpty();
+        return (attributeSnapshot == null || attributeSnapshot.isEmpty())
+                && (fkSnapshot == null || fkSnapshot.isEmpty());
     }
 
     public void clear() {
-        if(snapshot != null) {
-            snapshot.clear();
+        if(attributeSnapshot != null) {
+            attributeSnapshot.clear();
+        }
+        if(fkSnapshot != null) {
+            fkSnapshot.clear();
         }
         if(updatedAttributes != null) {
             updatedAttributes.clear();
@@ -148,12 +188,12 @@ public class Values {
     }
 
     public boolean isSameBatch(Values other) {
-        if(snapshot == null) {
-            return other.snapshot == null;
+        if(updatedAttributes == null) {
+            return other.updatedAttributes == null;
         }
-        if(other.snapshot == null) {
+        if(other.updatedAttributes == null) {
             return false;
         }
-        return snapshot.keySet().equals(other.snapshot.keySet());
+        return updatedAttributes.equals(other.updatedAttributes);
     }
 }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/MeaningfulFKIT.java b/cayenne-server/src/test/java/org/apache/cayenne/MeaningfulFKIT.java
index 2617db5..a993607 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/MeaningfulFKIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/MeaningfulFKIT.java
@@ -20,6 +20,7 @@
 package org.apache.cayenne;
 
 import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.SelectById;
 import org.apache.cayenne.testdo.relationships.MeaningfulFK;
 import org.apache.cayenne.testdo.relationships.RelationshipHelper;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
@@ -28,9 +29,7 @@ import org.apache.cayenne.unit.di.server.UseServerRuntime;
 import org.apache.cayenne.validation.ValidationResult;
 import org.junit.Test;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 @UseServerRuntime(CayenneProjects.RELATIONSHIPS_PROJECT)
 public class MeaningfulFKIT extends ServerCase {
@@ -57,12 +56,24 @@ public class MeaningfulFKIT extends ServerCase {
     public void testValidateForSave2() throws Exception {
         MeaningfulFK testObject = context.newObject(MeaningfulFK.class);
 
-        RelationshipHelper related = testObject.getObjectContext().newObject(
-                RelationshipHelper.class);
+        RelationshipHelper related = context.newObject(RelationshipHelper.class);
         testObject.setToRelationshipHelper(related);
 
         ValidationResult validation = new ValidationResult();
         testObject.validateForSave(validation);
         assertFalse(validation.hasFailures());
     }
+
+    @Test
+    public void testMeaningfulFKSet() {
+        MeaningfulFK testObject = context.newObject(MeaningfulFK.class);
+
+        RelationshipHelper related = context.newObject(RelationshipHelper.class);
+        testObject.setToRelationshipHelper(related);
+
+        context.commitChanges();
+
+        MeaningfulFK testObject2 = SelectById.query(MeaningfulFK.class, testObject.getObjectId()).selectOne(context);
+        assertNotEquals(0, testObject2.getRelationshipHelperID());
+    }
 }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/flush/operation/DbRowOpMergerTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/flush/operation/DbRowOpMergerTest.java
index 5e1261c..b673903 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/flush/operation/DbRowOpMergerTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/flush/operation/DbRowOpMergerTest.java
@@ -99,9 +99,9 @@ public class DbRowOpMergerTest {
         DbAttribute attr2 = new DbAttribute("attr2");
 
         InsertDbRowOp row1 = new InsertDbRowOp(mockObject(id), mockEntity(), id);
-        row1.getValues().addValue(attr1, 1);
+        row1.getValues().addValue(attr1, 1, false);
         InsertDbRowOp row2 = new InsertDbRowOp(mockObject(id), mockEntity(), id);
-        row2.getValues().addValue(attr2, 2);
+        row2.getValues().addValue(attr2, 2, false);
 
         {
             DbRowOpMerger merger = new DbRowOpMerger();
@@ -132,9 +132,9 @@ public class DbRowOpMergerTest {
         DbAttribute attr2 = new DbAttribute("attr2");
 
         UpdateDbRowOp row1 = new UpdateDbRowOp(mockObject(id), mockEntity(), id);
-        row1.getValues().addValue(attr1, 1);
+        row1.getValues().addValue(attr1, 1, false);
         UpdateDbRowOp row2 = new UpdateDbRowOp(mockObject(id), mockEntity(), id);
-        row2.getValues().addValue(attr2, 2);
+        row2.getValues().addValue(attr2, 2, false);
 
         {
             DbRowOpMerger merger = new DbRowOpMerger();
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/flush/operation/ValuesTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/flush/operation/ValuesTest.java
index af8c52e..1140b2b 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/flush/operation/ValuesTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/flush/operation/ValuesTest.java
@@ -73,7 +73,7 @@ public class ValuesTest {
 
         Values values = new Values(row, false);
         DbAttribute attr1 = new DbAttribute("attr1");
-        values.addValue(attr1, 32);
+        values.addValue(attr1, 32, false);
 
         assertEquals(Collections.singletonList(attr1), values.getUpdatedAttributes());
         assertEquals(Collections.singletonMap("attr1", 32), values.getSnapshot());
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_FkOfDifferentType.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_FkOfDifferentType.java
index e0a82da..2defec7 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_FkOfDifferentType.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_FkOfDifferentType.java
@@ -5,9 +5,7 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 
 import org.apache.cayenne.BaseDataObject;
-import org.apache.cayenne.exp.ExpressionFactory;
 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.testdo.relationships.RelationshipHelper;
 
@@ -21,7 +19,6 @@ public abstract class _FkOfDifferentType extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
-    public static final NumericProperty<Integer> ID_PK_PROPERTY = PropertyFactory.createNumeric(ExpressionFactory.dbPathExp("ID"), Integer.class);
     public static final String ID_PK_COLUMN = "ID";
 
     public static final EntityProperty<RelationshipHelper> RELATIONSHIP_HELPER = PropertyFactory.createEntity("relationshipHelper", RelationshipHelper.class);
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_MeaningfulFK.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_MeaningfulFK.java
index 9cdf064..30b89eb 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_MeaningfulFK.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_MeaningfulFK.java
@@ -5,7 +5,6 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 
 import org.apache.cayenne.BaseDataObject;
-import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.exp.property.EntityProperty;
 import org.apache.cayenne.exp.property.NumericProperty;
 import org.apache.cayenne.exp.property.PropertyFactory;
@@ -21,22 +20,21 @@ public abstract class _MeaningfulFK extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
-    public static final NumericProperty<Integer> MEANIGNFUL_FK_ID_PK_PROPERTY = PropertyFactory.createNumeric(ExpressionFactory.dbPathExp("MEANIGNFUL_FK_ID"), Integer.class);
     public static final String MEANIGNFUL_FK_ID_PK_COLUMN = "MEANIGNFUL_FK_ID";
 
     public static final NumericProperty<Integer> RELATIONSHIP_HELPER_ID = PropertyFactory.createNumeric("relationshipHelperID", Integer.class);
     public static final EntityProperty<RelationshipHelper> TO_RELATIONSHIP_HELPER = PropertyFactory.createEntity("toRelationshipHelper", RelationshipHelper.class);
 
-    protected Integer relationshipHelperID;
+    protected int relationshipHelperID;
 
     protected Object toRelationshipHelper;
 
-    public void setRelationshipHelperID(Integer relationshipHelperID) {
+    public void setRelationshipHelperID(int relationshipHelperID) {
         beforePropertyWrite("relationshipHelperID", this.relationshipHelperID, relationshipHelperID);
         this.relationshipHelperID = relationshipHelperID;
     }
 
-    public Integer getRelationshipHelperID() {
+    public int getRelationshipHelperID() {
         beforePropertyRead("relationshipHelperID");
         return this.relationshipHelperID;
     }
@@ -73,7 +71,7 @@ public abstract class _MeaningfulFK extends BaseDataObject {
 
         switch (propName) {
             case "relationshipHelperID":
-                this.relationshipHelperID = (Integer)val;
+                this.relationshipHelperID = val == null ? 0 : (int)val;
                 break;
             case "toRelationshipHelper":
                 this.toRelationshipHelper = val;
@@ -94,14 +92,14 @@ public abstract class _MeaningfulFK extends BaseDataObject {
     @Override
     protected void writeState(ObjectOutputStream out) throws IOException {
         super.writeState(out);
-        out.writeObject(this.relationshipHelperID);
+        out.writeInt(this.relationshipHelperID);
         out.writeObject(this.toRelationshipHelper);
     }
 
     @Override
     protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
         super.readState(in);
-        this.relationshipHelperID = (Integer)in.readObject();
+        this.relationshipHelperID = in.readInt();
         this.toRelationshipHelper = in.readObject();
     }
 
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_ReflexiveAndToOne.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_ReflexiveAndToOne.java
index 9f15c34..0843b5a 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_ReflexiveAndToOne.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_ReflexiveAndToOne.java
@@ -6,10 +6,8 @@ import java.io.ObjectOutputStream;
 import java.util.List;
 
 import org.apache.cayenne.BaseDataObject;
-import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.exp.property.EntityProperty;
 import org.apache.cayenne.exp.property.ListProperty;
-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.relationships.ReflexiveAndToOne;
@@ -25,7 +23,6 @@ public abstract class _ReflexiveAndToOne extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
-    public static final NumericProperty<Integer> REFLEXIVE_AND_TO_ONE_ID_PK_PROPERTY = PropertyFactory.createNumeric(ExpressionFactory.dbPathExp("REFLEXIVE_AND_TO_ONE_ID"), Integer.class);
     public static final String REFLEXIVE_AND_TO_ONE_ID_PK_COLUMN = "REFLEXIVE_AND_TO_ONE_ID";
 
     public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_RelationshipHelper.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_RelationshipHelper.java
index 3d4bd8c..30c5711 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_RelationshipHelper.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/relationships/auto/_RelationshipHelper.java
@@ -6,9 +6,7 @@ import java.io.ObjectOutputStream;
 import java.util.List;
 
 import org.apache.cayenne.BaseDataObject;
-import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.exp.property.ListProperty;
-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.relationships.FkOfDifferentType;
@@ -25,7 +23,6 @@ public abstract class _RelationshipHelper extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
-    public static final NumericProperty<Integer> RELATIONSHIP_HELPER_ID_PK_PROPERTY = PropertyFactory.createNumeric(ExpressionFactory.dbPathExp("RELATIONSHIP_HELPER_ID"), Integer.class);
     public static final String RELATIONSHIP_HELPER_ID_PK_COLUMN = "RELATIONSHIP_HELPER_ID";
 
     public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
diff --git a/cayenne-server/src/test/resources/cayenne-relationships.xml b/cayenne-server/src/test/resources/cayenne-relationships.xml
index 90524b9..6205fb2 100644
--- a/cayenne-server/src/test/resources/cayenne-relationships.xml
+++ b/cayenne-server/src/test/resources/cayenne-relationships.xml
@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <domain xmlns="http://cayenne.apache.org/schema/10/domain"
+	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain https://cayenne.apache.org/schema/10/domain.xsd"
 	 project-version="10">
 	<map name="relationships"/>
 </domain>
diff --git a/cayenne-server/src/test/resources/relationships.map.xml b/cayenne-server/src/test/resources/relationships.map.xml
index 55b9fda..b487db9 100644
--- a/cayenne-server/src/test/resources/relationships.map.xml
+++ b/cayenne-server/src/test/resources/relationships.map.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <data-map xmlns="http://cayenne.apache.org/schema/10/modelMap"
 	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap http://cayenne.apache.org/schema/10/modelMap.xsd"
+	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap https://cayenne.apache.org/schema/10/modelMap.xsd"
 	 project-version="10">
 	<property name="defaultPackage" value="org.apache.cayenne.testdo.relationships"/>
 	<db-entity name="FK_OF_DIFFERENT_TYPE">
@@ -24,7 +24,7 @@
 	</db-entity>
 	<obj-entity name="FkOfDifferentType" className="org.apache.cayenne.testdo.relationships.FkOfDifferentType" dbEntityName="FK_OF_DIFFERENT_TYPE"/>
 	<obj-entity name="MeaningfulFK" className="org.apache.cayenne.testdo.relationships.MeaningfulFK" dbEntityName="MEANINGFUL_FK">
-		<obj-attribute name="relationshipHelperID" type="java.lang.Integer" db-attribute-path="RELATIONSHIP_HELPER_ID"/>
+		<obj-attribute name="relationshipHelperID" type="int" db-attribute-path="RELATIONSHIP_HELPER_ID"/>
 	</obj-entity>
 	<obj-entity name="ReflexiveAndToOne" className="org.apache.cayenne.testdo.relationships.ReflexiveAndToOne" dbEntityName="REFLEXIVE_AND_TO_ONE">
 		<obj-attribute name="name" type="java.lang.String" db-attribute-path="NAME"/>
@@ -64,4 +64,17 @@
 	<obj-relationship name="fksOfDifferentType" source="RelationshipHelper" target="FkOfDifferentType" db-relationship-path="fksOfDifferentType"/>
 	<obj-relationship name="meanigfulFKs" source="RelationshipHelper" target="MeaningfulFK" db-relationship-path="meanigfulFKs"/>
 	<obj-relationship name="reflexiveAndToOneArray" source="RelationshipHelper" target="ReflexiveAndToOne" db-relationship-path="reflexiveAndToOneArray"/>
+	<cgen xmlns="http://cayenne.apache.org/schema/10/cgen">
+		<destDir>..\java</destDir>
+		<mode>entity</mode>
+		<template>templates/v4_1/subclass.vm</template>
+		<superTemplate>templates/v4_1/superclass.vm</superTemplate>
+		<outputPattern>*.java</outputPattern>
+		<makePairs>true</makePairs>
+		<usePkgPath>true</usePkgPath>
+		<overwrite>false</overwrite>
+		<createPropertyNames>false</createPropertyNames>
+		<createPKProperties>false</createPKProperties>
+		<client>false</client>
+	</cgen>
 </data-map>