merge() cascading by default?

View: New views
6 Messages — Rating Filter:   Alert me  

merge() cascading by default?

by cowwoc :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

When I merge() an Image object, EclipseLink seems to persist all objects referenced by the object. If I change to persist() it complains that one of the referenced object was transient but not cascaded.

I am expecting the same warning to be issued for merge(). The documentation says that the default cascade is none but the behavior seems otherwise. I am using EclipseLink 1.0.1.

Thank you,
Gili

Re: merge() cascading by default?

by cowwoc :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Here is the output I see with logging enabled.

I hope file attachments works with nabble :)
good.txt refers to the output I expect. bad.txt refers to the unexpected cascade.

good.txt
bad.txt

Gili

cowwoc wrote:
When I merge() an Image object, EclipseLink seems to persist all objects referenced by the object. If I change to persist() it complains that one of the referenced object was transient but not cascaded.

I am expecting the same warning to be issued for merge(). The documentation says that the default cascade is none but the behavior seems otherwise. I am using EclipseLink 1.0.1.

Thank you,
Gili

Re: merge() cascading by default?

by James Sutherland :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I think this is correct.

merge() and persist() are different operations.  Merge is merging from one detached copy of the object, into a managed object, if something is not cascade merge, it just doesn't need to merge that attribute.  For persist the new object is being made managed (itself, not a copy), so has to resolve all of its references.

However, I would expect the relation to just not be merged, not to be inserted.  Is the object you are merging new or existing?  How are the new object relations that are inserted mapped?  Perhaps include some example code.



Here is the output I see with logging enabled.

I hope file attachments works with nabble :)
good.txt refers to the output I expect. bad.txt refers to the unexpected cascade.

good.txt
bad.txt

Gili

cowwoc wrote:
When I merge() an Image object, EclipseLink seems to persist all objects referenced by the object. If I change to persist() it complains that one of the referenced object was transient but not cascaded.

I am expecting the same warning to be issued for merge(). The documentation says that the default cascade is none but the behavior seems otherwise. I am using EclipseLink 1.0.1.

Thank you,
Gili


Re: merge() cascading by default?

by cowwoc :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi James,

I am merging a new object where all its attributes are new, however when it goes to merge() the entity to disk I know for a fact the specification attribute already exists (which is why you see the insertion failure). I understand what you said about merging an instance and skipping any non-cascade attributes but I would expect the following operation to fail:

1) The entity being merged is new
2) One of the attributes points to a new entity but does not have cascade enabled

because clearly then you're trying to persist an incomplete object. The counter-example is if you're merging an existing entity. I agree that in such a case it should skip merging any attribute with cascade disabled (so long as the attribute is already persisted, if the attribute is new then I expect a failure).

Please confirm whether you agree with the above statements or which ones I have misunderstood. As for my specific use-case, I have class Image with attribute Specification (which you see getting inserted). The attribute is declared with the following annotations:

        @ManyToOne(optional = false, fetch = FetchType.LAZY)
        @JoinColumn(name = "specificationId")

Gili


I think this is correct.

merge() and persist() are different operations.  Merge is merging from one detached copy of the object, into a managed object, if something is not cascade merge, it just doesn't need to merge that attribute.  For persist the new object is being made managed (itself, not a copy), so has to resolve all of its references.

However, I would expect the relation to just not be merged, not to be inserted.  Is the object you are merging new or existing?  How are the new object relations that are inserted mapped?  Perhaps include some example code.


cowwoc wrote:
Here is the output I see with logging enabled.

I hope file attachments works with nabble :)
good.txt refers to the output I expect. bad.txt refers to the unexpected cascade.

good.txt
bad.txt

Gili

cowwoc wrote:
When I merge() an Image object, EclipseLink seems to persist all objects referenced by the object. If I change to persist() it complains that one of the referenced object was transient but not cascaded.

I am expecting the same warning to be issued for merge(). The documentation says that the default cascade is none but the behavior seems otherwise. I am using EclipseLink 1.0.1.

Thank you,
Gili

Re: merge() cascading by default?

by James Sutherland :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

It looks like for new objects they will just be registered entirely (persistence by reachablity/cascade all).  I'm not sure what the JPA spec says on this, as merge() is different than persist(), but it is probably worth logging a bug in EclipseLink to have this scenario reviewed.

Either way you are going to get an error, so best to fix your object that you are merging.



Hi James,

I am merging a new object where all its attributes are new, however when it goes to merge() the entity to disk I know for a fact the specification attribute already exists (which is why you see the insertion failure). I understand what you said about merging an instance and skipping any non-cascade attributes but I would expect the following operation to fail:

1) The entity being merged is new
2) One of the attributes points to a new entity but does not have cascade enabled

because clearly then you're trying to persist an incomplete object. The counter-example is if you're merging an existing entity. I agree that in such a case it should skip merging any attribute with cascade disabled (so long as the attribute is already persisted, if the attribute is new then I expect a failure).

Please confirm whether you agree with the above statements or which ones I have misunderstood. As for my specific use-case, I have class Image with attribute Specification (which you see getting inserted). The attribute is declared with the following annotations:

        @ManyToOne(optional = false, fetch = FetchType.LAZY)
        @JoinColumn(name = "specificationId")

Gili


I think this is correct.

merge() and persist() are different operations.  Merge is merging from one detached copy of the object, into a managed object, if something is not cascade merge, it just doesn't need to merge that attribute.  For persist the new object is being made managed (itself, not a copy), so has to resolve all of its references.

However, I would expect the relation to just not be merged, not to be inserted.  Is the object you are merging new or existing?  How are the new object relations that are inserted mapped?  Perhaps include some example code.


cowwoc wrote:
Here is the output I see with logging enabled.

I hope file attachments works with nabble :)
good.txt refers to the output I expect. bad.txt refers to the unexpected cascade.

good.txt
bad.txt

Gili

cowwoc wrote:
When I merge() an Image object, EclipseLink seems to persist all objects referenced by the object. If I change to persist() it complains that one of the referenced object was transient but not cascaded.

I am expecting the same warning to be issued for merge(). The documentation says that the default cascade is none but the behavior seems otherwise. I am using EclipseLink 1.0.1.

Thank you,
Gili


Re: merge() cascading by default?

by cowwoc :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I filed https://bugs.eclipse.org/bugs/show_bug.cgi?id=247662 but it looks like I might have jumped to conclusions (i.e. this behavior could be outside the JPA specification).

Here is what the TopLink documentation says:

http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html reads "By default, TopLink JPA does not cascade any persistence operations to the target of the association." and it goes on to list "merge" as a possible type of cascade, which behaves with the behavior we're seeing.

So at the very least, we seem to have a bug with respect to the TopLink documentation.

Now things get interesting... The JPA specification reads:

"3.2.4.1 Merging Detached Entity State

If X is a new entity instance, a new managed entity instance X' is created and the state of X is
copied into the new managed entity instance X'.

If X is an entity merged to X', with a reference to another entity Y, where cascade=MERGE or cascade=ALL is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y."

I believe the first paragraph is talking about new entities while the second paragraph is talking about persistent entities. The first paragraph doesn't say what happens if the new entity has associations and the second paragraph doesn't say what happens for new entities so my guess is that this situation is not explicitly covered by this section.

Still, if you read other sections of the specification, they say the default cascade is none and "the semantics of the flush operation" in section "3.2.3 Synchronization to the Database" reads:

"For any entity Y referenced by a relationship from X, where the relationship to Y has
not been annotated with the cascade element value cascade=PERSIST or cascade=ALL:

• If Y is new or removed, an IllegalStateException will be thrown by
the flush operation (and the transaction rolled back) or the transaction commit
will fail."

By extension, I believe it is fair to assume that the same behavior is expected for merge(), but you be the judge :)

Thanks,
Gili


It looks like for new objects they will just be registered entirely (persistence by reachablity/cascade all).  I'm not sure what the JPA spec says on this, as merge() is different than persist(), but it is probably worth logging a bug in EclipseLink to have this scenario reviewed.

Either way you are going to get an error, so best to fix your object that you are merging.



Hi James,

I am merging a new object where all its attributes are new, however when it goes to merge() the entity to disk I know for a fact the specification attribute already exists (which is why you see the insertion failure). I understand what you said about merging an instance and skipping any non-cascade attributes but I would expect the following operation to fail:

1) The entity being merged is new
2) One of the attributes points to a new entity but does not have cascade enabled

because clearly then you're trying to persist an incomplete object. The counter-example is if you're merging an existing entity. I agree that in such a case it should skip merging any attribute with cascade disabled (so long as the attribute is already persisted, if the attribute is new then I expect a failure).

Please confirm whether you agree with the above statements or which ones I have misunderstood. As for my specific use-case, I have class Image with attribute Specification (which you see getting inserted). The attribute is declared with the following annotations:

        @ManyToOne(optional = false, fetch = FetchType.LAZY)
        @JoinColumn(name = "specificationId")

Gili

James Sutherland wrote:
I think this is correct.

merge() and persist() are different operations.  Merge is merging from one detached copy of the object, into a managed object, if something is not cascade merge, it just doesn't need to merge that attribute.  For persist the new object is being made managed (itself, not a copy), so has to resolve all of its references.

However, I would expect the relation to just not be merged, not to be inserted.  Is the object you are merging new or existing?  How are the new object relations that are inserted mapped?  Perhaps include some example code.


cowwoc wrote:
Here is the output I see with logging enabled.

I hope file attachments works with nabble :)
good.txt refers to the output I expect. bad.txt refers to the unexpected cascade.

good.txt
bad.txt

Gili

cowwoc wrote:
When I merge() an Image object, EclipseLink seems to persist all objects referenced by the object. If I change to persist() it complains that one of the referenced object was transient but not cascaded.

I am expecting the same warning to be issued for merge(). The documentation says that the default cascade is none but the behavior seems otherwise. I am using EclipseLink 1.0.1.

Thank you,
Gili