JPA-like transparent persistence

50 views
Skip to first unread message

Владимир Коньков

unread,
Mar 31, 2021, 1:54:40 PM3/31/21
to Ebean ORM
Hi!

Does it possible to implement (or emulate) JPA-like (JDO, etc) transparent persistence with Ebean?

We very exited by Ebean querying capabilities  but our business logic is comparably complex and depends on fact that on commit all changes are flushed to DB. We use repositories and just can't/won't inject it everywhere where entity is changed. In such case code becoming very procedural and MyBatis-like. 

I know there is many cases where is fine-grained control of persistence process is good. But not in DDD-like code with non anemic domain model in witch entities actually 'talks' with others and changes each other. 

P.S.: currently we use Eclipselink with its batch fetch and other extensions and considering migration to Ebean.

Regards, 
Vladimir


Rob Bygrave

unread,
Mar 31, 2021, 7:12:50 PM3/31/21
to ebean@googlegroups
Ok, let me know if I misunderstood the questions but I think I understand.


> Does it possible to implement (or emulate) JPA-like (JDO, etc) transparent persistence with Ebean?

Specifically with JPA with beans still attached to the persistence context, on flush mutated/dirty beans are automatically persisted.  In comparison with Ebean where we expect to explicitly save() etc.

The question is, can Ebean simulate or do this such that we don't need to explicitly save() beans but instead auto persist mutated beans on flush/commit.  (I'll sort of answer below).



> on commit all changes are flushed to DB. We use repositories and just can't/won't inject it everywhere where entity is changed. In such case code becoming very procedural and MyBatis-like.

Right, I can picture that.


> I know there is many cases where is fine-grained control of persistence process is good. But not in DDD-like code with non anemic domain model in witch entities actually 'talks' with others and changes each other.

Ok, interesting. I don't think I have seen code quite like that. This is an interesting point and if possible I'd love to see a little example if you are able to share (obviously it might be code you are not allowed to share).


> P.S.: currently we use Eclipselink ...

Yes. I think we are seeing more of this.


Right, back to your original question.

> Does it possible to implement (or emulate) JPA-like (JDO, etc) transparent persistence with Ebean?

So does Ebean do this today?  No it does not.

Could we emulate it?  Maybe we could ...

Ebean has a PersistenceContext (io.ebean.bean.PersistenceContext, io.ebeaninternal.server.transaction.DefaultPersistenceContext). This PersistenceContext is held on the transaction (transaction scoped persistence context) and it holds all the beans that were loaded. These are the beans we would mutate (for updates). 

For the simple case of updating mutated beans:  It would be pretty much ... get the beans from the persistence context that are in dirty state, determine the order that they should be persisted (maybe the ordering of bean types does not matter per say), persist them - call database.save(dirtyBean).

What needs to be added, tested, thought about would be handling of insert and explicit delete's (orphan removal would be handled by database.save( dirtyBean )).  That is, I think it could be that we can still just do database.insert(bean) and database.delete(bean) as per normal - with batch persist on then these just go to the internal BatchControl held by the transaction so that should be fine.  There would be a question around if inserted beans should be added to the persistence context after a flush() [ideally they probably should for the case they are subsequently mutated and should be an update in a subsequent flush].

So emulating it might well be possible and not too tricky ... hmmm.

Note as a side point, that on SpiTransaction we have getPersistenceContext() and setPersistenceContext() - at this stage we have not had a good strong argument for exposing this in public API (via Transaction). If we got this all working then we could consider doing that to support "extended persistence context" - loading beans using one transaction, later transfering the persistence context to another transaction for doing more fetching and/or persisting.
  
Ok, probably worth writing some tests to simulate this and where the complexity is.  If we did manage to do this nicely then this likely would be an opt in option on a per transaction basis and globally (all transactions).

Note that when we have streaming queries findEach, findIterate, findStream ... these can use multiple persistence contexts (e.g. when iterating millions then we don't want all beans held in memory in the single persistence context) so we couldn't use this feature there but that should be expected. 


Next steps:

Create a test or 2 that "simulate" this and go from there.


--

---
You received this message because you are subscribed to the Google Groups "Ebean ORM" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ebean+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ebean/69ec2aeb-6169-44b0-afc7-afb6dc1f0530n%40googlegroups.com.

Rob Bygrave

unread,
Apr 1, 2021, 12:36:47 AM4/1/21
to ebean@googlegroups
So playing around and we have this PR: https://github.com/ebean-orm/ebean/pull/2213

This PR/branch would be pretty close to what we would be looking for. It definitely looks like Ebean can support a "transparent persistence" mode. If you are able to have a look at that PR and look at the tests and see this looks close to what you are looking for.  


>  handling of insert 

With transaction.isTransparentPersistence() inserted beans are added to the PersistenceContext. Such that if the inserted bean is flushed and then later mutated followed by a later flush/commit - it is detected that this bean is a "dirty bean in the PC" and we get the update.  We have a test passing for this, looks good.  If getGeneratedKeys is turned off the beans 


> and explicit delete's

With transaction.isTransparentPersistence() - we need an adjustment to internals such that the bean is marked as deleted in the PersistenceContext relatively early [before flush looks for dirty beans in the PC]. We have a test passing for this, looks good.




Next steps:
- Ponder if there is some case that we are missing / not handling. Review cases of ordering of inserts vs updates when cascade persist is not used perhaps?
- Ponder if we desire some ordering of the dirty beans that are updated [In theory it is not necessary but I think it would be good to ensure some consistent ordering of the updates]
- Add a global property to DatabaseConfig to support turning this feature on globally for all transactions. This supports the case where we want it on by default for all transactions and then we explicitly turn it off when desired.
- Add an option for @Transactional to explicitly turn it on or off - something like  @Transactional(mode=DEFAULT | EXPLICIT | TRANSPARENT)?


Cheers, Rob.

Владимир Коньков

unread,
Jun 14, 2021, 9:30:28 AM6/14/21
to Ebean ORM
Rob, thank you a lot for implementing transparent persistence in Ebean! It will simplify migration for JPA and JDO users.

While actively using new experimental transparent persistence future we found the first issue - changes of @*ToMany associations are not propagated to DB.

I've made PR that reproduces the issue:


https://github.com/ebean-orm/ebean/pull/2251
четверг, 1 апреля 2021 г. в 07:36:47 UTC+3, Rob Bygrave:
Reply all
Reply to author
Forward
0 new messages