[jboss-user] [Persistence, JBoss/CMP, Hibernate, Database] - Modify data within PreUpdate will only merges partially

Masterozz666 do-not-reply at jboss.com
Thu Apr 17 03:33:35 EDT 2008


Hi,

i have a problem with entity listeners using @PreUpdate to modify the data.
There are two entity beans, the first contains a collection of the second entity bean => OneToMany-Mapping. Something like that:


  | @Entity
  | @Table(name = "TEST_FIRSTBEAN")
  | public class FirstBean implements Serializable {
  | 
  | 	private static final long serialVersionUID = 8150999009636714523L;
  | 	
  | 	private Integer id;
  | 	private Integer state;
  | 	private Set<SecondBean> secondBeans = new HashSet<SecondBean>(0);
  | 	
  | 	public FirstBean() {
  | 	}
  | 
  | 	@Id
  | 	@GeneratedValue(strategy = GenerationType.AUTO)
  | 	@Column(name = "ID", unique = true, nullable = false, precision = 22, scale = 0)
  | 	public Integer getId() {
  | 		return this.id;
  | 	}
  | 
  | 	public void setId(Integer id) {
  | 		this.id = id;
  | 	}
  | 
  | 	@Column(name = "STATE")
  | 	public Integer getState() {
  | 		return this.state;
  | 	}
  | 
  | 	public void setState(Integer state) {
  | 		this.state = state;
  | 	}
  | 	
  | 	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "firstBean")
  | 	public Set<SecondBean> getSecondBeans() {
  | 		return this.secondBeans;
  | 	}
  | 
  | 	public void setSecondBeans(Set<SecondBean> bBeans) {
  | 		this.secondBeans = bBeans;
  | 	}
  | 
  | }
  | 

and


  | @Entity
  | @Table(name = "TEST_SECONDBEAN")
  | public class SecondBean implements Serializable {
  | 	private static final long serialVersionUID = -5353954801248924436L;
  | 	
  | 	private Integer id;
  | 	private Integer state;
  | 	private FirstBean firstBean;
  | 	
  | 	public SecondBean() {
  | 	}
  | 
  | 	@Id
  | 	@GeneratedValue(strategy = GenerationType.AUTO)
  | 	@Column(name = "ID", unique = true, nullable = false, precision = 22, scale = 0)
  | 	public Integer getId() {
  | 		return this.id;
  | 	}
  | 
  | 	public void setId(Integer id) {
  | 		this.id = id;
  | 	}
  | 
  | 	@Column(name = "STATE")
  | 	public Integer getState() {
  | 		return this.state;
  | 	}
  | 
  | 	public void setState(Integer state) {
  | 		this.state = state;
  | 	}
  | 	
  | 	@ManyToOne(fetch = FetchType.EAGER)
  | 	@JoinColumn(name = "FIRSTBEAN_ID")
  | 	public FirstBean getFirstBean() {
  | 		return this.firstBean;
  | 	}
  | 
  | 	public void setFirstBean(FirstBean firstBean) {
  | 		this.firstBean = firstBean;
  | 	}
  | 
  | }
  | 

There is also a simple entity listener. In the PreUpdate-Method It will set the state of the second beans, if the state of the first bean was set. Something like this:

  | public class FirstBeanEntityListener {
  | 	private static final Logger LOGGER = Logger.getLogger(FirstBeanEntityListener.class);
  | 	
  | 	public FirstBeanEntityListener() {
  | 		super();
  | 	}
  | 
  | 	@PreUpdate
  | 	public void preUpdate(final FirstBean bean) throws NamingException {
  | 		LOGGER.info("* FirstBean '"+bean.getName()+"' entity listener: @preUpdate called");
  | 		
  | 		if (bean != null && bean.getState() != null) {
  | 			LOGGER.info("  FirstBean '"+bean.getName()+"': state set");
  | 			
  | 			for (SecondBean childBeans : bean.getSecondBeans()) {
  | 				LOGGER.info("     set state for second bean: " + childBeans.getName());
  | 				childBeans.setState(new Integer(1));
  | 			}
  | 		}
  | 	}
  | 
  | }
  | 

The entity listener is bound to the entity bean using orm.xml:
<?xml version="1.0" encoding="UTF-8"?>
  | <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  | 	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
  | 	<entity class="FirstBean">
  | 		<entity-listeners>
  | 			<entity-listener class="FirstBeanEntityListener" />
  | 		</entity-listeners>
  | 	</entity>
  | </entity-mappings>

The problem is now: If i have one FirstBean with any number of second beans, and i set the state of the first bean on client side, merge it in a stateless session bean and look at the database after that, state of one SecondBean wasn't set, but all others are set. Assume a jUnit test like that:

public class EntityBeanListenerTest {
  | 
  | 	private TestServiceRemote testRemoteBean = null;
  | 
  | 	@Before
  | 	public void setUp() throws NamingException, RemoteCheckedException {
  | 		//Perform lookup:
  |         ...
  |         this.testRemoteBean = (TestServiceRemote) ctx.lookup("TestService");
  | 	}
  | 
  | 	@After
  | 	public void tearDown() throws Exception {
  | 		this.testRemoteBean = null;
  | 	}
  | 	
  | 	private FirstBean createSampleFirstBean() {
  | 		final FirstBean firstBean;
  | 		final SecondBean secondBean1;
  | 		final SecondBean secondBean2;
  | 		final SecondBean secondBean3;
  | 		
  | 		//Init first bean
  | 		firstBean = new FirstBean();
  | 		
  | 		//Init second beans
  | 		secondBean1 = new SecondBean();
  | 		secondBean2 = new SecondBean();
  | 		secondBean3 = new SecondBean();
  | 		
  | 		//Add second beans to first bean
  | 		firstBean.getSecondBeans().add(secondBean1);
  | 		firstBean.getSecondBeans().add(secondBean2);
  | 		firstBean.getSecondBeans().add(secondBean3);
  | 
  | 		secondBean1.setFirstBean(firstBean);
  | 		secondBean2.setFirstBean(firstBean);
  | 		secondBean3.setFirstBean(firstBean);
  | 		
  | 		return firstBean;
  | 	}
  | 
  | 	@Test
  | 	public void testFirstBeanDeletion() throws RemoteCheckedException {
  | 		FirstBean firstBean;
  | 		
  | 		//Reset database, will only clean table data
  | 		this.testRemoteBean.resetDatabase();
  | 		
  | 		//Create data
  | 		firstBean = this.createSampleFirstBean();
  | 		
  | 		//Save data and retrieve persisted data
  | 		this.testRemoteBean.persistFirstBean(firstBean);
  |         firstBean = this.testRemoteBean.getFirstBean();
  | 		
  | 		firstBean.setState(new Integer(1));
  | 		this.testRemoteBean.mergeFirstBean(firstBean);
  | 		firstBean = this.testRemoteBean.getFirstBean();
  | 		
  | 		for (final SecondBean secondBean : firstBean.getSecondBeans()) {
  |            //This will fail on one bean, which one is indeterministic
  | 			Assert.assertNotNull("Second beans have not been deleted", secondBean.getState());
  | 		}
  | 	}
  | 
  | }

I though the listeners should set all states of second beans, but for one second bean, the state wasn't set.
If i perform a flush after merging the data in the same transaction in the session bean, the jUnit test will pass.

Can anyone explain, why this happens? Am i doing something wrong? Must i always perform a flush?
I am using JBoss AS 4.2.2 GA.

Thanks in advance,

Markus

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4144737#4144737

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4144737



More information about the jboss-user mailing list