OPENJPA-2051: Change to ensure entities are properly cascaded after a flush.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1186903 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Heath Thomann 2011-10-20 16:37:15 +00:00
parent 16c76a0870
commit c8a84fd37d
6 changed files with 354 additions and 1 deletions

View File

@ -73,6 +73,8 @@ public class Compatibility {
private boolean _useListAttributeForArrays = false;
private boolean _metaFactoriesAreStrict = false;
private boolean _resetFlushFlagForCascadePersist = true;//OPENJPA-2051
/**
* Whether to require exact identity value types when creating object
@ -666,4 +668,32 @@ public class Compatibility {
public void setMetaFactoriesAreStrict(boolean metaFactoriesAreStrict) {
_metaFactoriesAreStrict = metaFactoriesAreStrict;
}
/**
* Whether OpenJPA should reset the internal state (flush flag) when cascading a persist to another
* Entity. That is, when a flush is performed, OpenJPA keep state to indicate the flush has been
* performed. In certain cascade persist scenarios the fact that a flush has been performed prior to
* a cascade persist can cause certain entities to not be written to the database given the prior
* flush. This property, when set, will cause the flush flag to be reset in cascade scenarios. For more
* details see JIRA OPENJPA-2051
*
* @since 2.0.x
*/
public boolean getResetFlushFlagForCascadePersist(){
return _resetFlushFlagForCascadePersist;
}
/**
* Whether OpenJPA should reset the internal state (flush flag) when cascading a persist to another
* Entity. That is, when a flush is performed, OpenJPA keep state to indicate the flush has been
* performed. In certain cascade persist scenarios the fact that a flush has been performed prior to
* a cascade persist can cause certain entities to not be written to the database given the prior
* flush. This property, when set, will cause the flush flag to be reset in cascade scenarios. For more
* details see JIRA OPENJPA-2051
*
* @since 2.0.x
*/
public void setResetFlushFlagForCascadePersist(boolean b){
_resetFlushFlagForCascadePersist = b;
}
}

View File

@ -4109,7 +4109,10 @@ public class BrokerImpl
lock();
try {
switch (status) {
case STATUS_INIT:
case STATUS_INIT:
if (_compat.getResetFlushFlagForCascadePersist()){//OPENJPA-2051
_flags &= ~FLAG_FLUSHED;
}
_cache.add(sm);
break;
case STATUS_TRANSIENT:

View File

@ -0,0 +1,59 @@
/*
* 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.cascade;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
@Entity
public class Edge {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long oid;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "SOURCE_OID")
private Vertex source;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "TARGET_OID")
private Vertex target;
protected Edge() {
}
Edge( Vertex src ) {
this();
this.source = src;
}
public void setTarget( Vertex node ) {
this.target = node;
}
public long getOid() {
return oid;
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.cascade;
import java.util.Collections;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
public class TestMultiCascadePersist extends SingleEMFTestCase {
@Override
public void setUp() throws Exception {
setUp(DROP_TABLES, Vertex.class, VertexType.class, Edge.class);
}
public void testSingleTransaction() {
OpenJPAEntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
//The flush is important to the rest of the test. If this
//is removed, the test works as expected. While the flush
//at this point in the test may seem odd/unnecessary, it
//is more clear to perform a flush directly rather than
//something (e.g. query) which would cause a flush under
//the covers. See OPENJPA-2051 for more details.
em.flush();
VertexType defaultType = new VertexType( "default" );
VertexType specialType = new VertexType( "special" );
em.persist(defaultType);
em.persist(specialType);
Vertex src = new Vertex( defaultType );
Vertex target = new Vertex( specialType );
Edge t = src.newEdge( target );
assertNotNull( t );
em.persist(src);
tx.commit();
TypedQuery<Edge> q = em.createQuery( "SELECT t FROM Edge t", Edge.class );
List<Edge> resultList = q.getResultList();
assertEquals( 1, resultList.size() );
assertEquals( 2, findAllVertexType(em).size() );
if (emf.getConfiguration().getCompatibilityInstance().getResetFlushFlagForCascadePersist()){
assertEquals( 2, findAllVertex(em).size() );
}
else{
//There *should* be 2 Vertex....but by default we can not fix this without a
//compatibility flag.
assertEquals( 1, findAllVertex(em).size() );
}
}
public VertexType findVertexTypeByName(EntityManager em, String name ) {
try {
TypedQuery<VertexType> query = em.createNamedQuery( "VertexType.findByName",
VertexType.class );
query.setParameter( 1, name );
return query.getSingleResult();
} catch ( NoResultException nre ) {
return null;
}
}
public List<VertexType> findAllVertexType(EntityManager em) {
try {
TypedQuery<VertexType> query = em.createNamedQuery( "VertexType.findAll",
VertexType.class );
return query.getResultList();
} catch ( NoResultException nre ) {
return Collections.emptyList();
}
}
public List<Vertex> findAllVertex(EntityManager em) {
try {
TypedQuery<Vertex> query = em.createNamedQuery( "Vertex.findAll",
Vertex.class );
return query.getResultList();
} catch ( NoResultException nre ) {
return Collections.emptyList();
}
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.cascade;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
@Entity
@NamedQueries({
@NamedQuery(name = "Vertex.findByName",
query = "SELECT n FROM Vertex n where n.type.name=?1"),
@NamedQuery(name = "Vertex.findAll", query = "SELECT n FROM Vertex n") })
public class Vertex {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long oid;
@OneToMany(mappedBy = "source", cascade = CascadeType.ALL)
private List<Edge> outgoing;
@OneToMany(mappedBy = "target", cascade = CascadeType.ALL)
private List<Edge> incoming;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "TYPE_OID")
private VertexType type;
protected Vertex() {
this.incoming = new ArrayList<Edge>();
this.outgoing = new ArrayList<Edge>();
}
public Vertex( VertexType type ) {
this();
this.type = type;
type.instances.add( this );
}
public Edge newEdge( Vertex target ) {
Edge t = new Edge( this );
outgoing.add( t );
t.setTarget( target );
return t;
}
public long getOid() {
return oid;
}
}

View File

@ -0,0 +1,66 @@
/*
* 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.cascade;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
@Entity
@NamedQueries({
@NamedQuery(name = "VertexType.findByName",
query = "SELECT t FROM VertexType t where t.name=?1"),
@NamedQuery(name = "VertexType.findAll",
query = "SELECT t FROM VertexType t") })
public class VertexType {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long oid;
@OneToMany(mappedBy = "type", cascade = CascadeType.ALL)
List<Vertex> instances;
private String name;
protected VertexType() {
this.instances = new ArrayList<Vertex>();
}
public VertexType( String name ) {
this();
this.name = name;
}
public String getName() {
return name;
}
public long getOid() {
return oid;
}
}