Home » Eclipse Projects » EclipseLink » 1.1.3 vs 2.0 equals
| |
Re: 1.1.3 vs 2.0 equals [message #501737 is a reply to message #501455] |
Thu, 03 December 2009 16:09 |
|
Not sure I understand, what do your mean by "clone"? You should only have a single version of each object in the persistence unit.
The PrePersist will be called on the identical object that your application called persist() on. The object should be a new object, and should only have references to other new objects, or other managed objects.
Is your PrePersist being called from a merge()? If so, then the object being persisted will be a copy of the object merge() was called with.
James : Wiki : Book : Blog : Twitter
|
|
| |
Re: 1.1.3 vs 2.0 equals [message #502223 is a reply to message #501741] |
Mon, 07 December 2009 09:44 |
Tom Eugelink Messages: 825 Registered: July 2009 |
Senior Member |
|
|
This is the simplified code in the Address child class. I inserted a println to show the hashcode of the compared entities.
@PrePersist @PreMerge
public void preSaveHook()
{
for (Address lAddress : getRelation().getAddressesWhereIAmRelation())
{
System.out.println( this.hashCode() + " vs " + lAddress.hashCode() );
if (!this.equals(lAddress))
{
...
}
}
}
There is one relation (master) with one new address (child), the relation is merged and the address is cascade persisted. This is the output:
17440602 vs 30741250
The compare happens between two different objects, both of class Address. If this is examined in debug mode all properties are identical, except:
- the "other" has a value for the @Id and @Version field, while for "this" these are null
- the "other" has no values for the relation property.
As mention in a previous post, in 1.1.3 this was different; neither the clone nor the original had @Id or @Version values and both had all fields set.
This is the stackstace, what seems important here is the method "registerNewObjectClone":
Thread [AWT-EventQueue-0] (Suspended)
Address.preSaveHook() line: 47
Address(AbstractBean<T>).prePersist() line: 250
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
PrivilegedAccessHelper.invokeMethod(Method, Object, Object[]) line: 346
EntityClassListener(EntityListener).invokeMethod(Method, Object, Object[], DescriptorEvent) line: 297
EntityClassListener.invokeMethod(String, DescriptorEvent) line: 64
EntityClassListener(EntityListener).prePersist(DescriptorEve nt) line: 399
DescriptorEventManager.notifyListener(DescriptorEventListene r, DescriptorEvent) line: 670
DescriptorEventManager.notifyEJB30Listeners(DescriptorEvent) line: 606
DescriptorEventManager.executeEvent(DescriptorEvent) line: 200
RepeatableWriteUnitOfWork(UnitOfWorkImpl).registerNewObjectC lone(Object, Object, ClassDescriptor) line: 4237
RepeatableWriteUnitOfWork.cloneAndRegisterNewObject(Object) line: 507
RepeatableWriteUnitOfWork(UnitOfWorkImpl).internalRegisterOb ject(Object, ClassDescriptor) line: 2902
RepeatableWriteUnitOfWork(UnitOfWorkImpl).registerObject(Obj ect, ClassDescriptor) line: 4326
RepeatableWriteUnitOfWork(UnitOfWorkImpl).registerObject(Obj ect) line: 4284
OneToManyMapping(CollectionMapping).buildElementClone(Object , Object, UnitOfWorkImpl, boolean) line: 242
IndirectListContainerPolicy(ContainerPolicy).addNextValueFro mIteratorInto(Object, Object, Object, CollectionMapping, UnitOfWorkImpl, boolean) line: 264
OneToManyMapping(CollectionMapping).buildCloneForPartObject( Object, Object, Object, UnitOfWorkImpl, boolean) line: 195
TransparentIndirectionPolicy.cloneAttribute(Object, Object, Object, UnitOfWorkImpl, boolean) line: 148
OneToManyMapping(ForeignReferenceMapping).buildClone(Object, Object, UnitOfWorkImpl) line: 172
ObjectBuilder.populateAttributesForClone(Object, Object, UnitOfWorkImpl) line: 2690
RepeatableWriteUnitOfWork.cloneAndRegisterNewObject(Object) line: 502
RepeatableWriteUnitOfWork(UnitOfWorkImpl).internalRegisterOb ject(Object, ClassDescriptor) line: 2902
MergeManager.registerObjectForMergeCloneIntoWorkingCopy(Obje ct) line: 841
MergeManager.mergeChangesOfCloneIntoWorkingCopy(Object) line: 473
MergeManager.mergeChanges(Object, ObjectChangeSet) line: 267
RepeatableWriteUnitOfWork(UnitOfWorkImpl).mergeCloneWithRefe rences(Object, MergeManager) line: 3486
RepeatableWriteUnitOfWork.mergeCloneWithReferences(Object, MergeManager) line: 301
RepeatableWriteUnitOfWork(UnitOfWorkImpl).mergeCloneWithRefe rences(Object, int, boolean) line: 3446
EntityManagerImpl.mergeInternal(Object) line: 414
EntityManagerImpl.merge(T) line: 391
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
EclipselinkEntityManagerExtender(EntityManagerExtender).invo ke(Object, Method, Object[]) line: 124
$Proxy3.merge(Object) line: not available
JpaObjectNavigatorModel$1.call() line: 812
JpaObjectNavigatorModel<T>.doSave() line: 825
JpaObjectNavigatorBar$4.actionPerformed(ActionEvent) line: 157
JButton(AbstractButton).fireActionPerformed(ActionEvent) line: 1995
AbstractButton$Handler.actionPerformed(ActionEvent) line: 2318
DefaultButtonModel.fireActionPerformed(ActionEvent) line: 387
DefaultButtonModel.setPressed(boolean) line: 242
BasicButtonListener.mouseReleased(MouseEvent) line: 236
AWTEventMulticaster.mouseReleased(MouseEvent) line: 272
JButton(Component).processMouseEvent(MouseEvent) line: 6263
JButton(JComponent).processMouseEvent(MouseEvent) line: 3267
JButton(Component).processEvent(AWTEvent) line: 6028
JButton(Container).processEvent(AWTEvent) line: 2041
JButton(Component).dispatchEventImpl(AWTEvent) line: 4630
JButton(Container).dispatchEventImpl(AWTEvent) line: 2099
JButton(Component).dispatchEvent(AWTEvent) line: 4460
LightweightDispatcher.retargetMouseEvent(Component, int, MouseEvent) line: 4574
LightweightDispatcher.processMouseEvent(MouseEvent) line: 4238
LightweightDispatcher.dispatchEvent(AWTEvent) line: 4168
JFrame(Container).dispatchEventImpl(AWTEvent) line: 2085
JFrame(Window).dispatchEventImpl(AWTEvent) line: 2478
JFrame(Component).dispatchEvent(AWTEvent) line: 4460
EventQueue.dispatchEvent(AWTEvent) line: 599
EventDispatchThread.pumpOneEventForFilters(int) line: 269
EventDispatchThread.pumpEventsForFilter(int, Conditional, EventFilter) line: 184
EventDispatchThread.pumpEventsForHierarchy(int, Conditional, Component) line: 174
EventDispatchThread.pumpEvents(int, Conditional) line: 169
EventDispatchThread.pumpEvents(Conditional) line: 161
EventDispatchThread.run() line: 122
|
|
|
Re: 1.1.3 vs 2.0 equals [message #502302 is a reply to message #502223] |
Mon, 07 December 2009 16:11 |
|
From your stack you are doing a merge() of the master, not a persist(). Merge must always create a clone of the objects, and the merged object is a clone.
Because the event is fired during the merge process, the state of its related objects may undefined, as it is in the processes of merging them.
James : Wiki : Book : Blog : Twitter
|
|
|
Re: 1.1.3 vs 2.0 equals [message #502357 is a reply to message #502302] |
Mon, 07 December 2009 19:05 |
Tom Eugelink Messages: 825 Registered: July 2009 |
Senior Member |
|
|
James wrote:
> From your stack you are doing a merge() of the master, not a
> persist(). Merge must always create a clone of the objects, and the
> merged object is a clone.
>
> Because the event is fired during the merge process, the state of its
> related objects may undefined, as it is in the processes of merging them.
I do not quite understand this. I have a new entity; it is persisted by relation, why is the action being done on the parent of influence on the action done on my new entity; it is new, it is persisted.
Secondly, in 1.1.3 the behavior was different:
- the @Id and @Version were not set on the clone
- the related entities were set
Why this changed so much? I had to strip down the equals method tremendously (take out both @Id, @Version and any non primary properties) which makes it far less accurate. If the state is undefined, can it please be undefined as it was in 1.1.3? :-)
Tom
|
|
|
Re: 1.1.3 vs 2.0 equals [message #502719 is a reply to message #501455] |
Wed, 09 December 2009 14:35 |
|
persist() and merge() are two different operations. persist takes a new object and make that instance managed in the persistence context.
merge() is for when you have a detached, or serialized copy of an object. You want to merge the changes from your copy, but not effect your detached copy in any way. So the new object being merged must remain detached, and a copy of it persisted.
I'm not exactly sure what changed between 1.1.3 and 2.0, but if 1.1.3 was calling the prePersist event before the copy had its Id or version set, then it would seem to be more correct in 2.0, as it would seem desirable for the object to have its Id.
EclipseLink does have other events, depending on what you are doing you may wish to look into those, such as the preInsert DescriptorEvent.
James : Wiki : Book : Blog : Twitter
|
|
|
Re: 1.1.3 vs 2.0 equals [message #502730 is a reply to message #502719] |
Wed, 09 December 2009 15:04 |
Tom Eugelink Messages: 825 Registered: July 2009 |
Senior Member |
|
|
> persist() and merge() are two different operations. persist takes a new
> object and make that instance managed in the persistence context.
>
> merge() is for when you have a detached, or serialized copy of an
> object. You want to merge the changes from your copy, but not effect
> your detached copy in any way. So the new object being merged must
> remain detached, and a copy of it persisted.
Ok. But given the situation where there is a master entity that already existed, so it needs to be merged, but it has a new child entity, which should be persisted...
Am I correct that a good approach could be to never use cascade persist or merge, and explicitly call persist on all objects? In that way the master is merged and the new child is persisted?
> EclipseLink does have other events, depending on what you are doing you
> may wish to look into those, such as the preInsert DescriptorEvent.
All I want is to compare and validate the properties of related entities before persist or merge. I'll take a look.
Tom
|
|
| | | |
new events [message #503037 is a reply to message #502993] |
Thu, 10 December 2009 16:15 |
Tom Eugelink Messages: 825 Registered: July 2009 |
Senior Member |
|
|
This is the code that I execute:
Relation lRelation = Relation.findByPK(100306); // this is just an EM.find(Relation.class, relationnr);
lRelation.setName(lRelation.getName() + "x");
Address lAddress = lRelation.getAddressesWhereIAmRelation().get(0);
lRelation.removeAddressesWhereIAmRelation(lAddress); // removes from collection and sets relation to null
lEntityManager.remove(lAddress);
lEntityManager.getTransaction().begin();
lEntityManager.merge(lRelation);
lEntityManager.getTransaction().commit();
I see that first an update is executed setting the relationnr to null
setBigDecimal=16034 / UPDATE address SET dwhmodified = ?, dwhby = ?, relationnr = ?, lazylock = ? WHERE ((addressnr = >>>HERE<<< ) AND (lazylock = ?))
setNull=-5 / UPDATE address SET dwhmodified = ?, relationnr = >>>HERE<<< , lazylock = ? WHERE ((addressnr = ?) AND (lazylock = ?))
And then immediately a delete
setBigDecimal=16034 / DELETE FROM address WHERE ((addressnr = >>>HERE<<< ) AND (lazylock = ?))
Why update then delete? There is no cascade merge...
@ManyToOne(fetch = FetchType.LAZY, targetEntity = nl.reinders.bm.Relation.class, cascade = {CascadeType.REFRESH} ) @JoinColumn(name="relationnr")
volatile protected nl.reinders.bm.Relation iRelation;
@OneToMany(mappedBy = "iRelation", fetch = FetchType.LAZY, targetEntity = nl.reinders.bm.Address.class, cascade = {CascadeType.REFRESH,CascadeType.REMOVE} )
volatile protected java.util.List<nl.reinders.bm.Address> iAddressesWhereIAmRelation = new java.util.ArrayList<nl.reinders.bm.Address>();
Tom
|
|
|
Re: new events [message #503749 is a reply to message #503037] |
Tue, 15 December 2009 15:46 |
|
The code is a little odd. Since you appear to be finding the lRelation in the same EntityManager, there is no point to calling merge() on it, as it is already managed. Also it is somewhat odd to be calling remove() before starting the transaction.
The UPDATE occurs before the DELETE because you are modifying the object, if you did not modify it then it would not be updated. Objects that are modified are updated before they are deleted because the update may be required for database constraints.
If you do not want the update, then don't modify the object. EclipseLink does also offer a performDeleteFirst option, but I would not recommend that. You could also refresh() it before calling remove() to clear your changes (or revert it in the UnitOfWork API), but I would recommend not modifying it if you do not want it updated.
James : Wiki : Book : Blog : Twitter
|
|
| |
Goto Forum:
Current Time: Wed Sep 25 09:09:39 GMT 2024
Powered by FUDForum. Page generated in 0.04597 seconds
|