mirror of https://github.com/apache/openjpa.git
OPENJPA-1053: fix update by setting an embeddable which contains a cascade delete relation with another entity.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@769879 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
14ae1c34cf
commit
1677b481b2
|
@ -2658,8 +2658,11 @@ public class BrokerImpl
|
|||
|
||||
// ACT_CASCADE
|
||||
if ((action & OpCallbacks.ACT_RUN) == 0) {
|
||||
if (sm != null)
|
||||
sm.cascadeDelete(call);
|
||||
if (sm != null) {
|
||||
if (!sm.isEmbedded() || !sm.getDereferencedEmbedDependent()) {
|
||||
sm.cascadeDelete(call);
|
||||
}
|
||||
}
|
||||
else
|
||||
cascadeTransient(OpCallbacks.OP_DELETE, obj, call, "delete");
|
||||
return;
|
||||
|
@ -2669,8 +2672,11 @@ public class BrokerImpl
|
|||
if (sm != null) {
|
||||
if (sm.isDetached())
|
||||
throw newDetachedException(obj, "delete");
|
||||
if ((action & OpCallbacks.ACT_CASCADE) != 0)
|
||||
sm.cascadeDelete(call);
|
||||
if ((action & OpCallbacks.ACT_CASCADE) != 0) {
|
||||
if (!sm.isEmbedded() || !sm.getDereferencedEmbedDependent()) {
|
||||
sm.cascadeDelete(call);
|
||||
}
|
||||
}
|
||||
sm.delete();
|
||||
} else if (assertPersistenceCapable(obj).pcIsDetached() == Boolean.TRUE)
|
||||
throw newDetachedException(obj, "delete");
|
||||
|
|
|
@ -302,8 +302,11 @@ class SingleFieldManager
|
|||
// immediate cascade works on field value; dependent deref
|
||||
// works on external value
|
||||
if ((immediate || fmd.isEmbeddedPC())
|
||||
&& fmd.getCascadeDelete() == ValueMetaData.CASCADE_IMMEDIATE)
|
||||
&& fmd.getCascadeDelete() == ValueMetaData.CASCADE_IMMEDIATE) {
|
||||
if (fmd.isEmbeddedPC())
|
||||
dereferenceEmbedDependent(_sm);
|
||||
delete(fmd, objval, call);
|
||||
}
|
||||
else if (fmd.getCascadeDelete() == ValueMetaData.CASCADE_AUTO)
|
||||
dereferenceDependent(fmd.getExternalValue(objval, _broker));
|
||||
return;
|
||||
|
@ -413,7 +416,11 @@ class SingleFieldManager
|
|||
if (sm != null)
|
||||
sm.setDereferencedDependent(true, true);
|
||||
}
|
||||
|
||||
|
||||
void dereferenceEmbedDependent(StateManagerImpl sm) {
|
||||
sm.setDereferencedEmbedDependent(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively invoke the broker to gather cascade-refresh objects in
|
||||
* the current field into the given set. This method is only called
|
||||
|
|
|
@ -107,6 +107,7 @@ public class StateManagerImpl
|
|||
private static final int FLAG_VERSION_CHECK = 2 << 14;
|
||||
private static final int FLAG_VERSION_UPDATE = 2 << 15;
|
||||
private static final int FLAG_DETACHING = 2 << 16;
|
||||
private static final int FLAG_EMBED_DEREF = 2 << 17;
|
||||
|
||||
private static final Localizer _loc = Localizer.forPackage
|
||||
(StateManagerImpl.class);
|
||||
|
@ -1300,6 +1301,18 @@ public class StateManagerImpl
|
|||
_broker.addDereferencedDependent(this);
|
||||
}
|
||||
}
|
||||
|
||||
void setDereferencedEmbedDependent(boolean deref) {
|
||||
if (!deref && (_flags & FLAG_EMBED_DEREF) > 0) {
|
||||
_flags &= ~FLAG_EMBED_DEREF;
|
||||
} else if (deref && (_flags & FLAG_EMBED_DEREF) == 0) {
|
||||
_flags |= FLAG_EMBED_DEREF;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getDereferencedEmbedDependent() {
|
||||
return ((_flags |= FLAG_EMBED_DEREF) == 0 ? false : true);
|
||||
}
|
||||
|
||||
///////////
|
||||
// Locking
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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.embed;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
@Embeddable
|
||||
public class Embed_MappedToOneCascadeDelete {
|
||||
protected String name1;
|
||||
protected String name2;
|
||||
protected String name3;
|
||||
|
||||
@OneToOne(mappedBy="entityA", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
protected EntityB2 bm;
|
||||
|
||||
|
||||
public String getName1() {
|
||||
return name1;
|
||||
}
|
||||
|
||||
public void setName1(String name1) {
|
||||
this.name1 = name1;
|
||||
}
|
||||
|
||||
public String getName2() {
|
||||
return name2;
|
||||
}
|
||||
|
||||
public void setName2(String name2) {
|
||||
this.name2 = name2;
|
||||
}
|
||||
|
||||
public String getName3() {
|
||||
return name3;
|
||||
}
|
||||
|
||||
public void setName3(String name3) {
|
||||
this.name3 = name3;
|
||||
}
|
||||
|
||||
public void setMappedEntityB(EntityB2 bm) {
|
||||
this.bm = bm;
|
||||
}
|
||||
|
||||
public EntityB2 getMappedEntityB() {
|
||||
return bm;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.embed;
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name="TB11A")
|
||||
public class EntityA_Embed_MappedToOneCascadeDelete implements Serializable {
|
||||
@Id
|
||||
Integer id;
|
||||
|
||||
@Column(length=30)
|
||||
String name;
|
||||
|
||||
@Basic(fetch=FetchType.LAZY)
|
||||
int age;
|
||||
|
||||
@Embedded
|
||||
protected Embed_MappedToOneCascadeDelete embed;
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(int age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Embed_MappedToOneCascadeDelete getEmbed() {
|
||||
return embed;
|
||||
}
|
||||
|
||||
public void setEmbed(Embed_MappedToOneCascadeDelete embed) {
|
||||
this.embed = embed;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.embed;
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
|
||||
@Entity
|
||||
public class EntityB2 implements Serializable {
|
||||
|
||||
@Id
|
||||
int id;
|
||||
|
||||
@Column(length=30)
|
||||
String name;
|
||||
|
||||
@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
EntityA_Embed_MappedToOneCascadeDelete entityA;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public EntityA_Embed_MappedToOneCascadeDelete getEntityA() {
|
||||
return entityA;
|
||||
}
|
||||
|
||||
public void setEntityA(EntityA_Embed_MappedToOneCascadeDelete entityA) {
|
||||
this.entityA = entityA;
|
||||
}
|
||||
}
|
||||
|
|
@ -79,7 +79,9 @@ public class TestEmbeddable extends SingleEMFTestCase {
|
|||
Employee3.class, EmployeeName3.class, Item1.class, Item2.class,
|
||||
Item3.class, Company1.class, Company2.class, Division.class,
|
||||
VicePresident.class, EntityA_Embed_MappedToOne.class,
|
||||
Embed_MappedToOne.class, DROP_TABLES);
|
||||
Embed_MappedToOne.class, Embed_MappedToOneCascadeDelete.class,
|
||||
EntityA_Embed_MappedToOneCascadeDelete.class, EntityB2.class,
|
||||
DROP_TABLES);
|
||||
}
|
||||
|
||||
public void testEntityA_Coll_String() {
|
||||
|
@ -160,6 +162,11 @@ public class TestEmbeddable extends SingleEMFTestCase {
|
|||
findObjMapKeyClass();
|
||||
}
|
||||
|
||||
public void testEntityA_Embed_MappedToOneCascadeDelete() {
|
||||
createEntityA_Embed_MappedToOneCascadeDelete();
|
||||
updateEntityA_Embed_MappedToOneCascadeDelete();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create EntityA_Coll_String
|
||||
*/
|
||||
|
@ -257,6 +264,80 @@ public class TestEmbeddable extends SingleEMFTestCase {
|
|||
return embed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create EntityA_Embed_MappedToOneCascadeDelete
|
||||
*/
|
||||
public void createEntityA_Embed_MappedToOneCascadeDelete() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
EntityTransaction tran = em.getTransaction();
|
||||
createEntityA_Embed_MappedToOneCascadeDelete(em, ID);
|
||||
tran.begin();
|
||||
em.flush();
|
||||
tran.commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
public void createEntityA_Embed_MappedToOneCascadeDelete(EntityManager em,
|
||||
int id) {
|
||||
EntityA_Embed_MappedToOneCascadeDelete a =
|
||||
new EntityA_Embed_MappedToOneCascadeDelete();
|
||||
a.setId(id);
|
||||
a.setName("a" + id);
|
||||
a.setAge(id);
|
||||
Embed_MappedToOneCascadeDelete embed =
|
||||
createEmbed_MappedToOneDeleteCascade(em, id, a);
|
||||
a.setEmbed(embed);
|
||||
em.persist(a);
|
||||
}
|
||||
|
||||
public Embed_MappedToOneCascadeDelete createEmbed_MappedToOneDeleteCascade(
|
||||
EntityManager em, int id, EntityA_Embed_MappedToOneCascadeDelete a) {
|
||||
Embed_MappedToOneCascadeDelete embed = new Embed_MappedToOneCascadeDelete();
|
||||
embed.setName1("name1");
|
||||
embed.setName2("name2");
|
||||
embed.setName3("name3");
|
||||
EntityB2 b = new EntityB2();
|
||||
b.setId(id);
|
||||
b.setName("bm" + id);
|
||||
b.setEntityA(a);
|
||||
embed.setMappedEntityB(b);
|
||||
em.persist(b);
|
||||
return embed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update EntityA_Embed_MappedToOneCascadeDelete
|
||||
*/
|
||||
public void updateEntityA_Embed_MappedToOneCascadeDelete() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
EntityTransaction tran = em.getTransaction();
|
||||
updateEntityA_Embed_MappedToOneCascadeDelete(em, ID);
|
||||
tran.begin();
|
||||
em.flush();
|
||||
tran.commit();
|
||||
em.clear();
|
||||
|
||||
EntityA_Embed_MappedToOneCascadeDelete a =
|
||||
em.find(EntityA_Embed_MappedToOneCascadeDelete.class, ID);
|
||||
assertNotNull(a);
|
||||
|
||||
EntityB2 b2 = em.find(EntityB2.class, ID);
|
||||
assertNotNull(b2);
|
||||
|
||||
em.close();
|
||||
}
|
||||
|
||||
public void updateEntityA_Embed_MappedToOneCascadeDelete(EntityManager em,
|
||||
int id) {
|
||||
EntityA_Embed_MappedToOneCascadeDelete a =
|
||||
em.find(EntityA_Embed_MappedToOneCascadeDelete.class, id);
|
||||
a.setName("newa" + id);
|
||||
a.setAge(id + 1);
|
||||
Embed_MappedToOneCascadeDelete embed =
|
||||
createEmbed_MappedToOneDeleteCascade(em, id+1, a);
|
||||
a.setEmbed(embed);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create EntityA_Coll_Embed_ToOne
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue