You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by jg...@apache.org on 2014/09/23 19:03:48 UTC
svn commit: r1627091 - in /openjpa/trunk:
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/
openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/
Author: jgrassel
Date: Tue Sep 23 17:03:48 2014
New Revision: 1627091
URL: http://svn.apache.org/r1627091
Log:
OPENJPA-2525: Use of JoinColumn targets to another joinColumn key exposed as an attribute will cause a ConstrainViolation exception on persist
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ACase.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AEvident.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AText.java (with props)
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestO2ORefColumn.java (with props)
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java?rev=1627091&r1=1627090&r2=1627091&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java Tue Sep 23 17:03:48 2014
@@ -14,7 +14,7 @@
* "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.
+ * under the License.
*/
package org.apache.openjpa.jdbc.sql;
@@ -35,6 +35,7 @@ import java.util.Locale;
import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.meta.FieldMapping;
import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
import org.apache.openjpa.jdbc.meta.Joinable;
import org.apache.openjpa.jdbc.meta.RelationId;
@@ -43,6 +44,8 @@ import org.apache.openjpa.jdbc.schema.Co
import org.apache.openjpa.jdbc.schema.ForeignKey;
import org.apache.openjpa.jdbc.schema.Table;
import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.util.InternalException;
@@ -284,15 +287,16 @@ public class RowImpl
else
val = join.getJoinValue(to, toCols[i], (JDBCStore) to.
getContext().getStoreManager().getInnermostDelegate());
-
+
if (set && val == null) {
if (canSet(io, i, true))
setNull(fromCols[i]);
} else if (set && val instanceof Raw)
setRaw(fromCols[i], val.toString());
- else if (set)
+ else if (set) {
setObject(fromCols[i], val, toCols[i].getJavaType(), false);
- else if (val == null)
+ setJoinRefColumn(to, fromCols, toCols[i], val);
+ } else if (val == null)
whereNull(fromCols[i]);
else if (val instanceof Raw)
whereRaw(fromCols[i], val.toString());
@@ -301,6 +305,37 @@ public class RowImpl
}
}
+ private void setJoinRefColumn(OpenJPAStateManager inverseSm, Column ownerCols[], Column inverseCol,
+ Object val) {
+ OpenJPAStateManager ownerSm = getPrimaryKey();
+ if (ownerSm != null) {
+ ClassMetaData ownerMeta = ownerSm.getMetaData();
+ // loop through all the fields in the owner entity
+ for (FieldMetaData ownerFM : ownerMeta.getFields()) {
+ // look for any single column in this field references the
+ // same column as the foreign key target column
+ Column cols[] = ((FieldMapping) ownerFM).getColumns();
+ if (cols.length == 1 // only support attribute of non-compound foreign key
+ && cols != ownerCols // not @Id field
+ && cols[0].getIdentifier().equals(ownerCols[0].getIdentifier())) {
+ // copy the foreign key value to the current field.
+ FieldMetaData inverseFM = inverseSm.getMetaData().getField(
+ inverseCol.getIdentifier().getName());
+ if (inverseFM != null) {
+ int inverseValIndex = inverseFM.getIndex();
+ Class<?> inverseType = inverseSm.getMetaData().getField(inverseValIndex).getType();
+ int ownerIndex = ownerFM.getIndex();
+ Class<?> ownerType = ownerSm.getMetaData().getField(ownerIndex).getType();
+ if (inverseType == ownerType) {
+ Object inverseVal = inverseSm.fetch(inverseValIndex);
+ ownerSm.storeField(ownerIndex, inverseVal);
+ }
+ }
+ }
+ }
+ }
+ }
+
/**
* Return true if any of the given column indexes are settable.
*/
@@ -682,11 +717,11 @@ public class RowImpl
// never set auto increment columns and honor column defaults
if (_action == ACTION_INSERT) {
if (col.isAutoAssigned()) {
- // OPENJPA-349: validate because this can be the only column
- setValid(true);
+ // OPENJPA-349: validate because this can be the only column
+ setValid(true);
return;
}
- if (!overrideDefault && val == null
+ if (!overrideDefault && val == null
&& col.getDefaultString() != null)
return;
}
@@ -959,19 +994,19 @@ public class RowImpl
if (isValid())
row.setValid(true);
}
-
+
public Object[] getVals() {
return _vals;
}
-
+
public int[] getTypes() {
return _types;
}
-
+
public boolean isFlushed() {
return _isFlushed;
}
-
+
public void setFlushed(boolean isFlushed) {
_isFlushed = isFlushed;
}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ACase.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ACase.java?rev=1627091&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ACase.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ACase.java Tue Sep 23 17:03:48 2014
@@ -0,0 +1,61 @@
+/*
+ * 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.openjpa.persistence.relations;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToOne;
+
+@Entity
+public class ACase {
+
+ private int id;
+ @Id
+ @GeneratedValue(strategy=GenerationType.IDENTITY)
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ private String name;
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private AText aText;
+ @OneToOne(fetch=FetchType.LAZY, mappedBy="aCase", cascade=CascadeType.MERGE)
+ public AText getAText() {
+ return aText;
+ }
+
+ public void setAText(AText aText) {
+ this.aText = aText;
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ACase.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AEvident.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AEvident.java?rev=1627091&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AEvident.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AEvident.java Tue Sep 23 17:03:48 2014
@@ -0,0 +1,63 @@
+/*
+ * 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.openjpa.persistence.relations;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+
+@Entity
+public class AEvident {
+
+ private int id;
+ @Id
+ @GeneratedValue(strategy=GenerationType.IDENTITY)
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ private String name;
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private AText aText;
+ @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.MERGE)
+ @JoinColumn(name="ACASE_ID", referencedColumnName="ACASE_ID")
+ public AText getAText() {
+ return aText;
+ }
+
+ public void setAText(AText aText) {
+ this.aText = aText;
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AEvident.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AText.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AText.java?rev=1627091&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AText.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AText.java Tue Sep 23 17:03:48 2014
@@ -0,0 +1,90 @@
+/*
+ * 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.openjpa.persistence.relations;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+
+@Entity
+public class AText {
+
+ private int id;
+ @Id
+ @GeneratedValue(strategy=GenerationType.IDENTITY)
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ private String name;
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ private ACase aCase;
+ @OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.MERGE)
+ @JoinColumn(name="ACASE_ID", nullable=false)
+ public ACase getACase() {
+ return aCase;
+ }
+
+ public void setACase(ACase aCase) {
+ this.aCase = aCase;
+ }
+
+
+ private Set<AEvident> aEvidents = new HashSet<AEvident>();
+ @OneToMany(targetEntity=AEvident.class, mappedBy="aText", cascade=CascadeType.MERGE)
+ public Set<AEvident> getAEvidents() {
+ return aEvidents;
+ }
+
+ public void setAEvidents(Set<AEvident> aEvidents) {
+ this.aEvidents = aEvidents;
+ }
+
+ private int aCaseId;
+ @Column(name="ACASE_ID", insertable=false, updatable=false, unique=true)
+ public int getACaseId() {
+ return aCaseId;
+ }
+
+ public void setACaseId(int aCaseId) {
+ this.aCaseId = aCaseId;
+ }
+
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/AText.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestO2ORefColumn.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestO2ORefColumn.java?rev=1627091&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestO2ORefColumn.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestO2ORefColumn.java Tue Sep 23 17:03:48 2014
@@ -0,0 +1,103 @@
+/*
+ * 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.openjpa.persistence.relations;
+
+import javax.persistence.EntityManager;
+
+import junit.framework.Assert;
+
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+/**
+ * Unit test to verify the foreign key of a Join column in an association (aText), that is exposed as an
+ * attribute, is updated after the entity is flushed or committed to the data store.
+ * See AText -> ACase's foreign key also exposed a non-insertable and non-updatable attribute 'aCaseId'.
+ *
+ * In the test case, if the aCaseId is not updated with the foreign key (aCase.id) value, an association
+ * of aText (aEvident) with JoinColumn(..referencedColumnName=..) overridden to non-standard foreign key,
+ * a constraint violation will occur when aEvident is persisted to the data store.
+ */
+public class TestO2ORefColumn extends SingleEMFTestCase {
+
+ public void setUp () {
+ setUp(CLEAR_TABLES,
+ ACase.class, AText.class, AEvident.class,
+ "openjpa.jdbc.MappingDefaults", "ForeignKeyDeleteAction=cascade,JoinForeignKeyDeleteAction=cascade"
+ );
+ }
+
+ public void testRefColumnJoinEntities () {
+ AEvident aEvident = new AEvident();
+ aEvident.setName("Evident_A");
+
+ AText aText = new AText();
+ aText.setName("Text_A");
+ aText.getAEvidents().add(aEvident);
+ aEvident.setAText(aText);
+
+ ACase aCase = new ACase();
+ aCase.setName ("Case_A");
+ aCase.setAText(aText);
+ aText.setACase(aCase);
+
+ EntityManager em = emf.createEntityManager ();
+ em.getTransaction().begin ();
+ em.persist(aEvident);
+ em.persist(aText);
+ em.persist(aCase);
+ em.getTransaction ().commit ();
+
+ verify(aCase, aText, aEvident);
+
+ em.clear();
+
+ ACase fACase = em.find(ACase.class, aCase.getId());
+ AText fAText = fACase.getAText();
+ AEvident fAEvident = fAText.getAEvidents().iterator().next();
+ verify(fACase, fAText, fAEvident);
+
+ em.close ();
+ }
+
+ private void verify(ACase aCase, AText aText, AEvident aEvident) {
+ Assert.assertNotNull(aCase);
+ Assert.assertNotNull(aText);
+ Assert.assertNotNull(aEvident);
+
+ Assert.assertTrue(aCase.getId() != 0);
+ Assert.assertTrue(aText.getId() != 0);
+ Assert.assertTrue(aEvident.getId() != 0);
+
+ Assert.assertEquals("Case_A", aCase.getName());
+ Assert.assertEquals("Text_A", aText.getName());
+ Assert.assertEquals("Evident_A", aEvident.getName());
+
+ Assert.assertNotNull(aCase.getAText());
+ Assert.assertSame(aCase.getAText(), aText);
+ Assert.assertNotNull(aText.getACase());
+ Assert.assertSame(aCase, aText.getACase());
+
+ Assert.assertEquals(aText.getACaseId(), aCase.getId());
+ Assert.assertNotNull(aText.getAEvidents());
+ Assert.assertTrue(aText.getAEvidents().iterator().hasNext());
+ Assert.assertSame(aEvident, aText.getAEvidents().iterator().next());
+ Assert.assertNotNull(aEvident.getAText());
+ Assert.assertSame(aText, aEvident.getAText());
+ }
+}
Propchange: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestO2ORefColumn.java
------------------------------------------------------------------------------
svn:eol-style = native