Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[eclipselink-users] Orphan Removal not working when, object is added to collection and then same object is removed from collection in same transaction.

Hello,

Problem Statement: 
---------------------------------
Orphan Removal not working when, object is added to collection and then same
object is removed from collection in same transaction.

Eclipselink Version: EclipseLink 2.6.0
JRE: JDK 1.7.0_55
Database : Oracle
Steps to reproduce issue:
1. Domain has set of DomainUser mapped as one-to-many with
orphan-removal="true"  and <cascade-all /> property set.
2. Start transaction.
3. Load existing Domain.
4. Add one DomainUser object in collection. Call merge on parent Domain
entity.
5. Remove same DomainUser object from collection. Call merge on parent
Domain entity.
6. Commit transaction.

Expectation is commit should not insert new DomainUser object in databse as
orphan-removal is set to "true" and <cascade-all /> property set. But still
commit fires insert query for new DomainUser object.

Important thing to note here is if we do entityManager.flush(); call before
step 5 mentioned above, then behaviour is as expected.
Due to flush call, DomainUser object is inserted in database.
Then again during commit call at the end delete query is fired to remove
this object.

This is problem, even without flush call, Eclipselink should ensure orphan
objects are not inserted in this case.

Can anybody help regarding this issue.

Example explaining the above scenario: 
--------------------------------------------------------------------------

Example code and Entities: 
--------------------------------------------------


package learning.service;

import java.text.ParseException;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import learning.entity.Domain;
import learning.entity.DomainKey;
import learning.entity.DomainUser;

public class OrphanRemovalTest {

	public static void main(String[] args) throws ParseException {

		EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("OrphanDeleteTest");
		EntityManager entityManager = entityManagerFactory.createEntityManager();
		try {
			EntityTransaction txn = entityManager.getTransaction();
			txn.begin();
			//Load existing domain from database
			DomainKey domainKey = new DomainKey();
			domainKey.setDomainId("Banking");
			Domain d = entityManager.getReference(Domain.class, domainKey);
			//Create user1
			DomainUser user1 = new DomainUser("Manager", "Manager_Name", d);
			//Add new user1 in collection and merge
			d.getDomainUsers().add(user1);
			entityManager.merge(d);
			//Remove same user1 from collection and merge
			d.getDomainUsers().remove(user1);
			entityManager.merge(d);
			//Expectation is commit should NOT insert user1 as orphan-removal is set
to "true" for domainUsers collection
			//But still commit fires insert query for user1, which is unexpected.
			txn.commit();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

package learning.entity;

import java.util.HashSet;
import java.util.Set;

public class Domain {

	private DomainKey domainKey;
	private String name;
	private String description;
	private Set<DomainUser> domainUsers = new HashSet<DomainUser>();

	public DomainKey getDomainKey() {

		return domainKey;
	}

	public void setDomainKey(DomainKey domainKey) {

		this.domainKey = domainKey;
	}

	public String getName() {

		return name;
	}

	public void setName(String name) {

		this.name = name;
	}

	public String getDescription() {

		return description;
	}

	public void setDescription(String description) {

		this.description = description;
	}

	public Set<DomainUser> getDomainUsers() {

		return domainUsers;
	}

	public void setDomainUsers(Set<DomainUser> domainUsers) {

		this.domainUsers = domainUsers;
	}

	@Override
	public String toString() {

		return "Domain [domainKey=" + domainKey + ", name=" + name
				+ ", description=" + description + ", domainUsers="
				+ domainUsers + "]";
	}
}

package learning.entity;

public class DomainKey {

	private String domainId;

	public String getDomainId() {

		return domainId;
	}

	public void setDomainId(String domainId) {

		this.domainId = domainId;
	}
}

package learning.entity;

public class DomainUser {

	private DomainUserKey domainUserKey;
	private String domainUserName;
	private Domain domain;

	public DomainUser() {
	}

	public DomainUser(String domainUserId, String domainUserName, Domain
domain) {

		DomainUserKey domainUserKey = new DomainUserKey();
		domainUserKey.setDomainUserId(domainUserId);
		this.setDomainUserKey(domainUserKey);
		this.setDomainUserName(domainUserName);
		this.setDomain(domain);
	}

	public Domain getDomain() {
		return domain;
	}

	public void setDomain(Domain domain) {
		this.domain = domain;
	}

	public DomainUserKey getDomainUserKey() {

		return domainUserKey;
	}

	public void setDomainUserKey(DomainUserKey domainUserKey) {

		this.domainUserKey = domainUserKey;
	}

	public String getDomainUserName() {

		return domainUserName;
	}

	public void setDomainUserName(String domainUserName) {

		this.domainUserName = domainUserName;
	}

	@Override
	public int hashCode() {

		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((domainUserKey == null) ? 0 : domainUserKey.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {

		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		DomainUser other = (DomainUser) obj;
		if (domainUserKey == null) {
			if (other.domainUserKey != null)
				return false;
		} else if (!domainUserKey.equals(other.domainUserKey))
			return false;
		return true;
	}

	@Override
	public String toString() {

		return "DomainUser [domainUserKey=" + domainUserKey
				+ ", domainUserName=" + domainUserName + "]";
	}
}



package learning.entity;

public class DomainUserKey {

	private String domainUserId;

	public String getDomainUserId() {

		return domainUserId;
	}

	public void setDomainUserId(String domainUserId) {

		this.domainUserId = domainUserId;
	}

	@Override
	public int hashCode() {

		final int prime = 31;
		int result = 1;
		result = prime * result + ((domainUserId == null) ? 0 :
domainUserId.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {

		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		DomainUserKey other = (DomainUserKey) obj;
		if (domainUserId == null) {
			if (other.domainUserId != null)
				return false;
		} else if ( !domainUserId.equals(other.domainUserId))
			return false;
		return true;
	}
}


Tables: 
------------
create  table TST_DOMAINS_B
(
DOMAIN_CODE varchar2(100),
DOMAIN_NAME varchar2(100),
DOMAIN_DESC varchar2(100)
);

create  table TST_DOMAINS_USERS_B
(
DOMAIN_USER_ID varchar2(100),
DOMAIN_USER_NAME varchar2(100),
DOMAIN_CODE_FK varchar2(100)
);

insert into TST_DOMAINS_B (DOMAIN_CODE, DOMAIN_NAME, DOMAIN_DESC)
values ('Banking', 'Banking', 'Banking');

Mappings: 
----------------

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.4"
	xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/orm";
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
	xsi:schemaLocation="http://www.eclipse.org/eclipselink/xsds/persistence/orm
http://www.eclipse.org/eclipselink/xsds/eclipselink_orm_2_4.xsd";>

	<entity class="learning.entity.Domain">
		

		

		<attributes>
			<embedded-id attribute-type="learning.entity.DomainKey"
				name="domainKey">
				<attribute-override name="domainId">
					<column name="DOMAIN_CODE" />
				</attribute-override>

			</embedded-id>
			<basic name="name">
				<column name="DOMAIN_NAME" />
			</basic>
			<basic name="description">
				<column name="DOMAIN_DESC" />
			</basic>

			<one-to-many attribute-type="java.util.Set" fetch="LAZY"
				name="domainUsers" orphan-removal="true"
target-entity="learning.entity.DomainUser"
				mapped-by="domain">
				<join-column name="DOMAIN_CODE_FK"
					referenced-column-name="DOMAIN_CODE" nullable="false" />
				<cascade>
					<cascade-all />
				</cascade>
				<cascade-on-delete>true</cascade-on-delete>
				<private-owned />
			</one-to-many>

		</attributes>
	</entity>

	<entity class="learning.entity.DomainUser">
		

		

		<attributes>
			<embedded-id attribute-type="learning.entity.DomainUserKey"
				name="domainUserKey">
				<attribute-override name="domainUserId">
					<column name="DOMAIN_USER_ID" />
				</attribute-override>

			</embedded-id>
			<basic name="domainUserName">
				<column name="DOMAIN_USER_NAME" />
			</basic>

			<many-to-one name="domain" target-entity="learning.entity.Domain">
				<join-column name="DOMAIN_CODE_FK"
					referenced-column-name="DOMAIN_CODE" nullable="false" />
			</many-to-one>

		</attributes>
	</entity>

	<embeddable class="learning.entity.DomainKey">
		<attributes>
			<basic attribute-type="java.lang.String" name="domainId" />
		</attributes>
	</embeddable>

	<embeddable class="learning.entity.DomainUserKey">
		<attributes>
			<basic attribute-type="java.lang.String" name="domainUserId" />
		</attributes>
	</embeddable>
</entity-mappings>



--
View this message in context: http://eclipse.1072660.n5.nabble.com/Orphan-Removal-not-working-when-object-is-added-to-collection-and-then-same-object-is-removed-from-c-tp175873.html
Sent from the EclipseLink - Users mailing list archive at Nabble.com.


Back to the top