This is an automated email from the ASF dual-hosted git repository.
ntimofeev pushed a commit to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/STABLE-4.2 by this push:
new 105a8e2bc CAY-2840 Vertical Inheritance: Missing subclass attributes
with joint prefetch
105a8e2bc is described below
commit 105a8e2bc9b60a5b0db37191dc70a4a898d58120
Author: Jadon Hansell <[email protected]>
AuthorDate: Mon Feb 5 22:58:28 2024 +0400
CAY-2840 Vertical Inheritance: Missing subclass attributes with joint
prefetch
(cherry picked from commit 2358f52a9c7728751ddc5aea68f973a84f1c8f35)
---
RELEASE-NOTES.txt | 1 +
.../select/DescriptorColumnExtractor.java | 6 ++++-
.../cayenne/access/VerticalInheritanceIT.java | 30 ++++++++++++++++++++++
.../testdo/inheritance_vertical/auto/_IvBase.java | 25 ++++++++++++++++++
.../testdo/inheritance_vertical/auto/_IvOther.java | 19 ++++++++++++++
.../test/resources/inheritance-vertical.map.xml | 9 +++++++
6 files changed, 89 insertions(+), 1 deletion(-)
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index ab27b4664..cf9643a37 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -20,6 +20,7 @@ CAY-2809 Cayenne Expression grammar doesn't allow custom
function as an argument
CAY-2810 Can't use custom operator expression with aggregate functions
CAY-2813 Regression: Constants.CI_PROPERTY flag is no longer working for MySQL
CAY-2815 Incorrect translation of aliased expression
+CAY-2840 Vertical Inheritance: Missing subclass attributes with joint prefetch
----------------------------------
Release: 4.2
diff --git
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java
index 1cb72ff1a..ad4ee573f 100644
---
a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java
+++
b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/DescriptorColumnExtractor.java
@@ -128,7 +128,11 @@ class DescriptorColumnExtractor extends
BaseColumnExtractor implements PropertyV
}
if (count > 1) {
// it was a flattened attribute, so need to keep full path
info
- String dataRowKey = result.getAttributePaths().get(i) +
"." + dbAttribute.getName();
+ String attributePath = result.getAttributePaths().get(i);
+ if (attributePath.startsWith(PREFETCH_PREFIX)) {
+ attributePath =
attributePath.substring(PREFETCH_PREFIX.length());
+ }
+ String dataRowKey = attributePath + "." +
dbAttribute.getName();
resultNodeDescriptor.setDataRowKey(dataRowKey);
addEntityResultField(dataRowKey);
} else {
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
index a0cf075f7..320f22051 100644
---
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
+++
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
@@ -682,6 +682,36 @@ public class VerticalInheritanceIT extends ServerCase {
assertEquals(2,
ObjectSelect.query(IvImpl.class).selectCount(context));
}
+ /**
+ * @link https://issues.apache.org/jira/browse/CAY-2840
+ */
+ @Test
+ public void testJointPrefetchBelongsTo() throws SQLException {
+ TableHelper ivOtherTable = new TableHelper(dbHelper,
"IV_OTHER");
+ ivOtherTable.setColumns("ID", "NAME",
"BASE_ID").setColumnTypes(Types.INTEGER, Types.VARCHAR, Types.INTEGER);
+
+ TableHelper ivBaseTable = new TableHelper(dbHelper, "IV_BASE");
+ ivBaseTable.setColumns("ID", "NAME",
"TYPE").setColumnTypes(Types.INTEGER, Types.VARCHAR, Types.CHAR);
+
+ TableHelper ivImplTable = new TableHelper(dbHelper, "IV_IMPL");
+ ivImplTable.setColumns("ID",
"ATTR1").setColumnTypes(Types.INTEGER, Types.VARCHAR);
+
+ ivBaseTable.insert(1, "Impl 1", "I");
+ ivImplTable.insert(1, "attr1");
+ ivOtherTable.insert(1, "other1", 1);
+
+ IvOther other =
ObjectSelect.query(IvOther.class).prefetch(IvOther.BASE.joint()).selectOne(context);
+ assertNotNull(other);
+ assertNotNull(other.getBase());
+
assertTrue(IvImpl.class.isAssignableFrom(other.getBase().getClass()));
+
+ IvImpl impl = (IvImpl)other.getBase();
+ // Ensure that base attributes were prefetched correctly
+ assertEquals("Impl 1", impl.getName());
+ // Ensure that subclass attributes were prefetched correctly
+ assertEquals("attr1", impl.getAttr1());
+ }
+
/**
* @link https://issues.apache.org/jira/browse/CAY-2282
*/
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvBase.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvBase.java
index 97c2e182f..dbc850c03 100644
---
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvBase.java
+++
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvBase.java
@@ -4,9 +4,12 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.util.List;
import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.ListProperty;
import org.apache.cayenne.exp.property.PropertyFactory;
import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.inheritance_vertical.IvOther;
/**
* Class _IvBase was generated by Cayenne.
@@ -22,10 +25,12 @@ public abstract class _IvBase extends BaseDataObject {
public static final StringProperty<String> NAME =
PropertyFactory.createString("name", String.class);
public static final StringProperty<String> TYPE =
PropertyFactory.createString("type", String.class);
+ public static final ListProperty<IvOther> OTHERS =
PropertyFactory.createList("others", IvOther.class);
protected String name;
protected String type;
+ protected Object others;
public void setName(String name) {
beforePropertyWrite("name", this.name, name);
@@ -47,6 +52,19 @@ public abstract class _IvBase extends BaseDataObject {
return this.type;
}
+ public void addToOthers(IvOther obj) {
+ addToManyTarget("others", obj, true);
+ }
+
+ public void removeFromOthers(IvOther obj) {
+ removeToManyTarget("others", obj, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<IvOther> getOthers() {
+ return (List<IvOther>)readProperty("others");
+ }
+
@Override
public Object readPropertyDirectly(String propName) {
if(propName == null) {
@@ -58,6 +76,8 @@ public abstract class _IvBase extends BaseDataObject {
return this.name;
case "type":
return this.type;
+ case "others":
+ return this.others;
default:
return super.readPropertyDirectly(propName);
}
@@ -76,6 +96,9 @@ public abstract class _IvBase extends BaseDataObject {
case "type":
this.type = (String)val;
break;
+ case "others":
+ this.others = val;
+ break;
default:
super.writePropertyDirectly(propName, val);
}
@@ -94,6 +117,7 @@ public abstract class _IvBase extends BaseDataObject {
super.writeState(out);
out.writeObject(this.name);
out.writeObject(this.type);
+ out.writeObject(this.others);
}
@Override
@@ -101,6 +125,7 @@ public abstract class _IvBase extends BaseDataObject {
super.readState(in);
this.name = (String)in.readObject();
this.type = (String)in.readObject();
+ this.others = in.readObject();
}
}
diff --git
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvOther.java
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvOther.java
index 075309868..1d681139d 100644
---
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvOther.java
+++
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvOther.java
@@ -6,9 +6,11 @@ import java.io.ObjectOutputStream;
import java.util.List;
import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.EntityProperty;
import org.apache.cayenne.exp.property.ListProperty;
import org.apache.cayenne.exp.property.PropertyFactory;
import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.inheritance_vertical.IvBase;
import org.apache.cayenne.testdo.inheritance_vertical.IvImpl;
import org.apache.cayenne.testdo.inheritance_vertical.IvImplWithLock;
@@ -25,11 +27,13 @@ public abstract class _IvOther extends BaseDataObject {
public static final String ID_PK_COLUMN = "ID";
public static final StringProperty<String> NAME =
PropertyFactory.createString("name", String.class);
+ public static final EntityProperty<IvBase> BASE =
PropertyFactory.createEntity("base", IvBase.class);
public static final ListProperty<IvImpl> IMPLS =
PropertyFactory.createList("impls", IvImpl.class);
public static final ListProperty<IvImplWithLock> IMPLS_WITH_LOCK =
PropertyFactory.createList("implsWithLock", IvImplWithLock.class);
protected String name;
+ protected Object base;
protected Object impls;
protected Object implsWithLock;
@@ -43,6 +47,14 @@ public abstract class _IvOther extends BaseDataObject {
return this.name;
}
+ public void setBase(IvBase base) {
+ setToOneTarget("base", base, true);
+ }
+
+ public IvBase getBase() {
+ return (IvBase)readProperty("base");
+ }
+
public void addToImpls(IvImpl obj) {
addToManyTarget("impls", obj, true);
}
@@ -78,6 +90,8 @@ public abstract class _IvOther extends BaseDataObject {
switch(propName) {
case "name":
return this.name;
+ case "base":
+ return this.base;
case "impls":
return this.impls;
case "implsWithLock":
@@ -97,6 +111,9 @@ public abstract class _IvOther extends BaseDataObject {
case "name":
this.name = (String)val;
break;
+ case "base":
+ this.base = val;
+ break;
case "impls":
this.impls = val;
break;
@@ -120,6 +137,7 @@ public abstract class _IvOther extends BaseDataObject {
protected void writeState(ObjectOutputStream out) throws IOException {
super.writeState(out);
out.writeObject(this.name);
+ out.writeObject(this.base);
out.writeObject(this.impls);
out.writeObject(this.implsWithLock);
}
@@ -128,6 +146,7 @@ public abstract class _IvOther extends BaseDataObject {
protected void readState(ObjectInputStream in) throws IOException,
ClassNotFoundException {
super.readState(in);
this.name = (String)in.readObject();
+ this.base = in.readObject();
this.impls = in.readObject();
this.implsWithLock = in.readObject();
}
diff --git a/cayenne-server/src/test/resources/inheritance-vertical.map.xml
b/cayenne-server/src/test/resources/inheritance-vertical.map.xml
index 9c2939727..4fa04258a 100644
--- a/cayenne-server/src/test/resources/inheritance-vertical.map.xml
+++ b/cayenne-server/src/test/resources/inheritance-vertical.map.xml
@@ -66,6 +66,7 @@
<db-attribute name="OTHER1_ID" type="INTEGER"
isMandatory="true"/>
</db-entity>
<db-entity name="IV_OTHER">
+ <db-attribute name="BASE_ID" type="INTEGER"/>
<db-attribute name="ID" type="INTEGER" isPrimaryKey="true"
isMandatory="true"/>
<db-attribute name="NAME" type="VARCHAR" length="100"/>
</db-entity>
@@ -202,6 +203,9 @@
<db-relationship name="impl" source="IV_BASE" target="IV_IMPL"
toDependentPK="true">
<db-attribute-pair source="ID" target="ID"/>
</db-relationship>
+ <db-relationship name="others" source="IV_BASE" target="IV_OTHER"
toMany="true">
+ <db-attribute-pair source="ID" target="BASE_ID"/>
+ </db-relationship>
<db-relationship name="impl" source="IV_BASE_WITH_LOCK"
target="IV_IMPL_WITH_LOCK" toDependentPK="true">
<db-attribute-pair source="ID" target="ID"/>
</db-relationship>
@@ -229,6 +233,9 @@
<db-relationship name="other1" source="IV_IMPL_WITH_LOCK"
target="IV_OTHER">
<db-attribute-pair source="OTHER1_ID" target="ID"/>
</db-relationship>
+ <db-relationship name="base" source="IV_OTHER" target="IV_BASE">
+ <db-attribute-pair source="BASE_ID" target="ID"/>
+ </db-relationship>
<db-relationship name="impls" source="IV_OTHER" target="IV_IMPL"
toMany="true">
<db-attribute-pair source="ID" target="OTHER_ID"/>
</db-relationship>
@@ -263,11 +270,13 @@
<db-attribute-pair source="IV_ROOT_ID" target="ID"/>
</db-relationship>
<obj-relationship name="x" source="Iv2Sub1" target="Iv2X"
deleteRule="Nullify" db-relationship-path="sub1.x"/>
+ <obj-relationship name="others" source="IvBase" target="IvOther"
deleteRule="Deny" db-relationship-path="others"/>
<obj-relationship name="children" source="IvConcrete"
target="IvConcrete" deleteRule="Deny" db-relationship-path="children"/>
<obj-relationship name="parent" source="IvConcrete" target="IvConcrete"
deleteRule="Nullify" db-relationship-path="parent"/>
<obj-relationship name="other1" source="IvImpl" target="IvOther"
deleteRule="Nullify" db-relationship-path="impl.other1"/>
<obj-relationship name="other2" source="IvImpl" target="IvOther"
deleteRule="Nullify" db-relationship-path="impl.other2"/>
<obj-relationship name="other1" source="IvImplWithLock"
target="IvOther" deleteRule="Nullify" db-relationship-path="impl.other1"/>
+ <obj-relationship name="base" source="IvOther" target="IvBase"
deleteRule="Nullify" db-relationship-path="base"/>
<obj-relationship name="impls" source="IvOther" target="IvImpl"
deleteRule="Deny" db-relationship-path="impls.base"/>
<obj-relationship name="implsWithLock" source="IvOther"
target="IvImplWithLock" deleteRule="Deny" db-relationship-path="impls.base"/>
<obj-relationship name="ivRoot" source="IvSub3" target="IvRoot"
deleteRule="Nullify" db-relationship-path="sub3.ivRoot1"/>