Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » @Version field does partially update?
@Version field does partially update? [message #387016] Tue, 07 April 2009 08:32 Go to next message
Christian Eugster is currently offline Christian Eugster
Messages: 134
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
Hi,

I have a problem with the @Version annotated field. Working with a
Superclass 'AbstractEntity with the fields annotated with @Id and @Version
and two subclasses, say Parent and Child, where Parent has a @OneToMany to
Child, I try to update the parent object containing several already
persistent children using the merge method. In the database (mysql 5.0)
the version field is updated (oldValue + 1), but in the entities property
(int version, annotated with @Version), the value stays the same. A second
merge fails then, because the version field in the database is higher than
that in the entity.

Has anybody an idea what I am doing wrong?

Thank you in advance!

Christian
Re: @Version field does partially update? [message #387023 is a reply to message #387016] Tue, 07 April 2009 13:17 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

Are you re-merging the same object? When you merge, you are merging into
the managed clone of the object, the version will be updated in the
managed clone, not the object you are merging. merge() returns the
managed object, you should use this object or a copy of it for any other
changes.

---
James
http://www.nabble.com/EclipseLink---Users-f26658.html


James : Wiki : Book : Blog : Twitter
Re: @Version field does partially update? [message #387039 is a reply to message #387023] Wed, 08 April 2009 20:02 Go to previous messageGo to next message
Christian Eugster is currently offline Christian Eugster
Messages: 134
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
Hi James,
I mean, that I use the same object, but maybe I understand the mechanism
not perfectly. Anyway, I have this problem just with one class. All entity
classes inherit the property version from the superclass (annotated with
@MappedSuperclass). All other subclasses merge without any problems. Also
I use for the different classes the same routine. Can you give me a hint
where to look? In the eclipselink wiki I found nothing that could have
helped me.
Thank you!
Re: @Version field does partially update? [message #387070 is a reply to message #387039] Thu, 09 April 2009 13:39 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

If your code is working for some objects and not others then there must be
something different in the object it is not working in.

Please include your merge code, and the code for the class it does not
work in, its superclass, and one of the classes it does work in.

---
James


James : Wiki : Book : Blog : Twitter
Re: @Version field does partially update? [message #387097 is a reply to message #387070] Wed, 15 April 2009 14:41 Go to previous messageGo to next message
Christian Eugster is currently offline Christian Eugster
Messages: 134
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
Hi James,

This is the Superclass:
8<-------------------------------------------------
package ch.eugster.colibri.persistence.entities;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.persistence.Version;

import org.eclipse.persistence.annotations.ConversionValue;
import org.eclipse.persistence.annotations.Convert;
import org.eclipse.persistence.annotations.ObjectTypeConverter;

@MappedSuperclass
@ObjectTypeConverter(name = "booleanConverter", dataType =
java.lang.Short.class, objectType = java.lang.Boolean.class,
conversionValues =
{ @ConversionValue(dataValue = "0", objectValue = "false"),
@ConversionValue(dataValue = "1", objectValue = "true") },
defaultObjectValue = "false")
public abstract class AbstractEntity
{
protected static long counter = 0l;

public static boolean DEBUG = true;

protected static void out(String output)
{
if (AbstractEntity.DEBUG)
{
System.out.println(output);
}
}

protected static void err(String error)
{
System.err.println(error);
}

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;

protected long timestamp;

@Convert("booleanConverter")
protected boolean deleted;

@Version
protected int version;

@Transient
protected PropertyChangeSupport propertyChangeSupport = new
PropertyChangeSupport(this);

public AbstractEntity()
{
}

public Long getId()
{
return this.id;
}

public void setId(Long id)
{
this.propertyChangeSupport.firePropertyChange("id", this.id, this.id =
id);
}

public long getTimestamp()
{
return this.timestamp;
}

public void setTimestamp(long timestamp)
{
this.propertyChangeSupport.firePropertyChange("timestamp",
this.timestamp,
this.timestamp = timestamp);
}

public boolean isDeleted()
{
return this.deleted;
}

public void setDeleted(boolean deleted)
{
this.propertyChangeSupport.firePropertyChange("deleted", this.deleted,
this.deleted = deleted);
}

public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener)
{
this.propertyChangeSupport.addPropertyChangeListener(propert yName,
listener);
}

public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener)
{
this.propertyChangeSupport.removePropertyChangeListener(prop ertyName,
listener);
}

public int getVersion()
{
return this.version;
}

public void setVersion(int version)
{
this.version = version;
}

protected String getString(String string)
{
return string == null ? "" : string;
}

@Override
public int hashCode()
{
if (this.id == null)
return Integer.MIN_VALUE;
else
{
return Integer.MIN_VALUE + this.id.intValue();
}
}

@Override
public boolean equals(Object object)
{
if (object == null) return false;

if (this.getClass().equals(object.getClass()))
{
AbstractEntity bt = (AbstractEntity) object;
return this.hashCode() == bt.hashCode();
}

return false;
}

}
8<-------------------------------------------------

And this is the class that fails to merge after the first merge:

8<-------------------------------------------------
/*
* Created on 17.12.2008
*
* To change the template for this generated file go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
package ch.eugster.colibri.persistence.entities;

import static javax.persistence.CascadeType.ALL;
import static javax.persistence.FetchType.EAGER;

import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@AttributeOverrides(
{
@AttributeOverride(name = "id", column = @Column(name = "tab_id",
updatable = false, unique = true)),
@AttributeOverride(name = "version", column = @Column(name =
"tab_version")),
@AttributeOverride(name = "timestamp", column = @Column(name =
"tab_timestamp")),
@AttributeOverride(name = "deleted", column = @Column(name =
"tab_deleted")) })
@Table(name = "colibri_tab")
public class Tab extends AbstractEntity implements Comparable<Tab>
{
@ManyToOne(cascade = ALL)
@JoinColumn(name = "tab_configurable_id", referencedColumnName =
"configurable_id")
private Configurable configurable;

@Basic
@Column(name = "tab_name")
private String name;

@Basic
@Column(name = "tab_rows")
private int rows;

@Basic
@Column(name = "tab_cols")
private int cols;

@Basic
@Column(name = "tab_pos")
private int pos;

@OneToMany(cascade = CascadeType.ALL, fetch = EAGER, mappedBy = "tab")
private Collection<Key> keys = new ArrayList<Key>();

public Tab()
{
super();
}

public Tab(Configurable configurable)
{
super();
this.setConfigurable(configurable);
}

public Configurable getConfigurable()
{
return this.configurable;
}

public void setConfigurable(Configurable configurable)
{
this.propertyChangeSupport.firePropertyChange("configurable ",
this.configurable,
this.configurable = configurable);
}

public String getName()
{
return this.getString(this.name);
}

public void setName(String name)
{
this.propertyChangeSupport.firePropertyChange("name", this.name,
this.name = name);
}

public int getRows()
{
return this.rows;
}

public void setRows(int rows)
{
this.propertyChangeSupport.firePropertyChange("rows", this.rows,
this.rows = rows);
}

public int getCols()
{
return this.cols;
}

public void setCols(int cols)
{
this.propertyChangeSupport.firePropertyChange("cols", this.cols,
this.cols = cols);
}

public int getPos()
{
return this.pos;
}

public void setPos(int pos)
{
this.propertyChangeSupport.firePropertyChange("pos", this.pos, this.pos
= pos);
}

public Collection<Key> getKeys()
{
return this.keys;
}

public void addKey(Key key)
{
if (key != null)
if (!this.keys.contains(key))
this.propertyChangeSupport
.firePropertyChange("keys", this.keys, this.keys.add(key));
}

public void removeKey(Key key)
{
if (key != null)
if (this.keys.contains(key))
this.propertyChangeSupport.firePropertyChange("keys", this.keys,
this.keys
.remove(key));
}

public void setKeys(Collection<Key> keys)
{
this.propertyChangeSupport.firePropertyChange("keys", this.keys,
this.keys = keys);
}

public int compareTo(Tab other)
{
return other.getPos() - this.getPos();
}
}
8<-------------------------------------------------

And this is a class that merges successfully:

8<-------------------------------------------------
/*
* Created on 17.12.2008
*
* To change the template for this generated file go to
* Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
*/
package ch.eugster.colibri.persistence.entities;

import static javax.persistence.CascadeType.ALL;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@AttributeOverrides(
{
@AttributeOverride(name = "id", column = @Column(name = "stock_id",
updatable = false, unique = true)),
@AttributeOverride(name = "version", column = @Column(name =
"stock_version")),
@AttributeOverride(name = "timestamp", column = @Column(name =
"stock_timestamp")),
@AttributeOverride(name = "deleted", column = @Column(name =
"stock_deleted")) })
@Table(name = "colibri_stock")
public class Stock extends AbstractEntity
{
@ManyToOne(cascade = ALL)
@JoinColumn(name = "stock_salespoint_id", referencedColumnName =
"salespoint_id")
private Salespoint salespoint;

@ManyToOne(cascade = ALL)
@JoinColumn(name = "stock_payment_type_id", referencedColumnName =
"payment_type_id")
private PaymentType paymentType;

@Basic
@Column(name = "stock_amount")
private double amount;

@Basic
@Column(name = "stock_variable")
private boolean variable;

public Stock()
{
super();
}

public Stock(Salespoint salespoint)
{
super();
this.setSalespoint(salespoint);
}

public Stock(Salespoint salespoint, PaymentType paymentType)
{
this.setSalespoint(salespoint);
this.setPaymentType(paymentType);
}

public Salespoint getSalespoint()
{
return this.salespoint;
}

public void setSalespoint(Salespoint salespoint)
{
this.propertyChangeSupport.firePropertyChange("salespoint",
this.salespoint,
this.salespoint = salespoint);
}

public PaymentType getPaymentType()
{
return this.paymentType;
}

public void setPaymentType(PaymentType paymentType)
{
this.propertyChangeSupport.firePropertyChange("paymentType",
this.paymentType,
this.paymentType = paymentType);
}

public double getAmount()
{
return this.amount;
}

public void setAmount(double amount)
{
this.propertyChangeSupport.firePropertyChange("amount", this.amount,
this.amount = amount);
}

public boolean isVariable()
{
return this.variable;
}

public void setVariable(boolean variable)
{
this.propertyChangeSupport.firePropertyChange("variable", this.variable,
this.variable = variable);
}

}
8<-------------------------------------------------

The code to update the objects is in the editor and as follows:

8<-------------------------------------------------
@Override
public void doSave(IProgressMonitor monitor)
{
if (this.validate())
{
this.saveValues();
AbstractEntityEditorInput input = (AbstractEntityEditorInput)
this.getEditorInput();
AbstractEntity entity = input.getEntity();
try
{
if (input.hasParent())
{
Repository.getCurrent().store(entity, true);
Repository.getCurrent().refresh(input.getParent());
}
else
Repository.getCurrent().store(entity);
this.setDirty(false);
this.scrolledForm.setText(this.getText());
this.updateControls();

}
catch (PersistenceException e)
{
if (e.getErrorCode().equals(PersistenceException.ErrorCode.SQL_ 4002))
{
Shell shell = this.getSite().getShell();
Message msg = this.getMessage(e.getErrorCode());
new MessageDialog(shell, msg.getTitle(), null, msg.getMessage(),
MessageDialog.WARNING, new String[]
{ Messages.AbstractEntityEditor_ok }, 0).open();

this.setFocus(msg.getControl());
}
}
}
}

The called method of the previous method (store):

public void store(AbstractEntity entity, boolean silent, boolean
updateTimestamp)
throws PersistenceException
{
try
{
boolean tx = this.beginTransaction();
WriteType type = this.doStore(entity, updateTimestamp);
if (tx) this.commitTransaction();
if (!silent) this.repository.fireWriteDatabaseEvent(new
WriteEvent(entity, type));
}
catch (Exception e)
{
e.printStackTrace();

Throwable cause = e.getCause();
if (cause instanceof DatabaseException)
{
DatabaseException de = (DatabaseException) cause;
throw new PersistenceException(de);
}
else if (cause instanceof javax.persistence.OptimisticLockException)
{
org.eclipse.persistence.exceptions.OptimisticLockException ole =
(org.eclipse.persistence.exceptions.OptimisticLockException) cause
.getCause();
throw new PersistenceException(ole);
}
}
finally
{
this.rollbackTransaction();
}
}
8<-------------------------------------------------

and the code that updates (merges) the object is as follows:

8<-------------------------------------------------
private WriteType doStore(AbstractEntity entity, boolean updateTimestamp)
{
if (updateTimestamp)
entity.setTimestamp(GregorianCalendar.getInstance().getTimeI nMillis());

if (entity.getId() == null)
{
this.entityManager.persist(entity);
return WriteType.INSERT;
}
else
{
this.entityManager.merge(entity);
return WriteType.UPDATE;
}
}
8<-------------------------------------------------

I hope that that helps you to see into my code...

Thank you

Christian
Re: @Version field does partially update? [message #387100 is a reply to message #387070] Thu, 16 April 2009 09:41 Go to previous message
Christian Eugster is currently offline Christian Eugster
Messages: 134
Registered: July 2009
Location: St. Gallen Switzerland
Senior Member
Hi James,

I did resolve my problem. It was as you said. I did not you further the
merged object. Sorry!

Christian
Previous Topic:@ManyToOne relation problem
Next Topic:Eclipselink JTA without jndi
Goto Forum:
  


Current Time: Sat Oct 25 04:19:32 GMT 2014

Powered by FUDForum. Page generated in 0.02320 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software