Thanks guys for all the effort in digging into the issue here. From a
pragmatic point of view I guess #2 would be my preferred option and then
think about what we should do with that save thing :) Maybe a strategy
pattern similar to what we have for TX would be the way to go.

The documentation does not put a focus on it, but Data is in no way
exclusively dependent on EntityRepository resp. AbstractEntityRepository -
those are just convenience constructs which I have seen in almost any team
I've worked popping up when it comes to JPA usage. With delegates [1] you
can actually build your own convenience base repositories they way they
should be ;) Also other features like criteria support have been moved to
their own interfaces and can be pulled in on demand.

Hope that helps,
Thomas

[1] http://deltaspike.apache.org/documentation/data.html#QueryDelegates

On Thu, Aug 13, 2015 at 6:21 PM, Marvin Toll <marvint...@gtcgroup.com>
wrote:

> Am in strong agreement with Harald's statement:
>
> "I never really liked the fact that save() blurs the distinction between
> persist() and merge(), and by its very name it encourages users to always
> call save() after changing an entity state which is usually unnecessary and
> sometimes even wrong - so far, I've seen each and every new user of
> DeltaSpike Data doing that."
>
> Having used near-native JPA2 for about 3.5 years I'm having an awkward
> time mentally mapping the "Data" module absraction to native JPA.  Said
> another way, I become a bit confused trying to remember how native JPA2
> works and how the DeltaSpike abstraction works.  However, this potential
> criticism is made without me having adequate time/experience with
> DeltaSpike Data... and may simply be my own transition discomfort.
>
>
> A wild idea... would you consider a less intrusive abstraction for a Data2
> module?  One that does not try to mirror Spring (or the Repository Pattern)
> but rather seeks to extend the JPA2 API?
>
>
> _Marvin
>
> -----Original Message-----
> From: Harald Wellmann [mailto:hwellmann...@gmail.com]
> Sent: Wednesday, August 12, 2015 5:46 PM
> To: dev@deltaspike.apache.org
> Subject: Issues with EntityRepository.save()
>
> This is a quick summary of the issues around EntityRepository.save() that
> seem to exist since 1.4.2.
>
> I'll create test cases and JIRA issues as time permits, but I think these
> notes may be helpful at this stage to find out whether or not
> incompatibilities experienced by other users have the same root cause.
>
> According to Javadoc [1], this is what save() does:
>
> "Persist (new entity) or merge the given entity. The distinction on
> calling either method is done based on the primary key field being null or
> not. If this results in wrong behavior for a specific case, consider using
> the EntityManagerDelegate which offers both persist and merge."
>
> As far as I can see, the description accurately describes the behaviour in
> 1.4.1.
>
> The behaviour was changed in 1.4.2 in an incompatible way without adapting
> the documentation. Since 1.4.2, if the primary key is not null, DeltaSpike
> also runs a database query to check whether an entity with the given key
> exists. If so, it calls merge(), otherwise persist().
>
> So there are now quite a few cases when save() calls persist() where it
> would have called merge() in 1.4.1.
>
> Some use cases:
>
> Use case 1:
>
> // assume separate transactions.
> foo = save(foo);
> remove(foo);
> foo = save(foo);
>
> Result in 1.4.1:
> foo is persistent. The second save() is a merge().
>
> Result in 1.4.2:
> Exception. The second save() is a persist(), since the key no longer
> exists. But then Hibernate complains it cannot persist a detached entity.
>
> Use case 2:
>
> Assume a one-to-many association Blog -> Comment, both with auto-generated
> identities of type long.
>
> public Blog createBlog(List<Comment> comments) {
>      Blog = new Blog();
>      blog.setComments(comments);
>      blog = blogRepository.save(blog);
>      blog.getComments().add(new Comment()); }
>
> Now someone calls createBlog(Arrays.asList(c1, c2)).
>
> In 1.4.1 this call succeeds. In 1.4.2, there is an
> UnsupportedOperationException since blog.getComments() is immutable.
>
> In 1.4.1, the identity member is 0. 0 is not null, so save() performs a
> merge(). merge() creates a new blog instance with a new mutable comments
> list (at least with Hibernate (PersistentBag)).
>
> In 1.4.2, there is no existing blog entity with identity 0, so save()
> calls persist() and returns the original blog instance. Its comments member
> is the result of Arrays.asList() which is immutable.
>
> Sometimes it is useful to question the things you think you know, like "an
> entity with an identity value of 0 or null cannot be persistent". I
> searched the JPA 2.1 spec and did not find a word about zero identities.
> In fact, Eclipselink has an option to *enable* zero identities
> (eclipselink.allow-zero-id).
>
> The exception from Hibernate is also misleading. Just because an entity
> passed to persist() has a non-null and non-zero key, it does not have to be
> detached, it may well be a new transient entity.
>
> I never really liked the fact that save() blurs the distinction between
> persist() and merge(), and by its very name it encourages users to always
> call save() after changing an entity state which is usually unnecessary and
> sometimes even wrong - so far, I've seen each and every new user of
> DeltaSpike Data doing that.
>
> At the moment, I don't see a way to specify and implement save() in a way
> that is logically consistent *and* portable across JPA providers.
> (I'll be happy to be proved false.)
>
> So for the next release we should do one of the following:
>
> 1) Adapt Javadoc to the current behaviour and document the
> incompatibilities.
>
> 2) Leave Javadoc unchanged and restore compatibility.
>
> 3) Specify a new expected behaviour and adapt both Javadoc and
> implementation.
>
> 4) Add a big fat warning to save() Javadoc and move persist() and
> merge() from EntityManagerDelegate to EntityRepository.
>
> [1]
>
> http://deltaspike.apache.org/javadoc/1.4.2/org/apache/deltaspike/data/api/EntityRepository.html#save-E-
>
> Regards,
> Harald
>
>

Reply via email to