JPA Best practice for managing entities in extended Persistence Context - java

I am using CDI conversation scoped, Seam managed extended persistence context (PC). This provides more fine-grained control over PC and avoids LIEs. I am using CDI Beans instead of EJB Beans. In a page, I retrieve list of entities and show them in a table. The selected entity record from the table is binded to the form and can be edited but not persisted until the "save" button is clicked. In this place the problem occurs, since all entities are managed the edited entities are also persisted when I try to flush/commit only one current entity in save action. What is the preferred best-practice approach to this kind of problems. Should I use middle POJO between the managed entity and the viewed/edited one? Should I detach then merge (before saving) the current in-progress entity? Any suggestions?
JPA 2.0, Hibernate 4.x
Seam 3 (Weld CDI, persistence, transaction, faces modules)
JSF 2.1
Java EE 6.

We used a similar approach but with EJB3 beans and without the Seam persistence context. Nevertheless, maybe our experience could be useful to you.
The idea was :
use an extended PersistenceContext in the bean
make all methods without transaction - otherwise your entities will be committed after the call
make the save method the one with a transaction.
Detaching the entities will kill the benefit of giving entities to the front, as you will throw LazyException each time you're trying to access something that wasn't loaded. It would be quite the same as use some DTO.
Hope it helps!

If i understand correctly, then:
Entity objects are displayed on a page
The user can make changes to those objects
The user can save an object to commit the changes to the database
I think the right approach here would be to detach the objects when they are edited, and then reattach them (by merging) when they are saved. That keeps the unsaved changes in memory only.
You don't actually need an extended persistence context for this, because any objects you need to keep between requests will be detached.

I am using Primefaces in front end and it was ajax submitting by default the changes made to the entity. The problem gone away after I have managed the Primefaces components.

Related

How to stop auto commit in EJB-JPA tx

I have a stateless EBJ and I am using JPA to manage database interactions. Below is my scenario where I need your help.
EJB received the call to fetch data (getCustomer()).
GetCustomer is used to read Customer entity from database using JPA.
The customer entity is having a method to remove spaces from attributes. which is annotated with #PostLoad. Basically this modifies the entity within persistence context.
Now when response is sent to client (after transaction completed ), its fires an update SQL to database to update the dataset (modified in step-3).
If you can see this operation, its a read-only in nature. But as my data is having lot many spaces, hence I have to trim it within entity object. But this approach is firing an update SQL which is not expected.
Could you please let me know the best approach to fix this issue or how to isolate and synchronize) EJB tx and JPA tx.
You can declare your getCustomer() to not support transactions:
#TransactionAttribute(NOT_SUPPORTED)
public Customer getCustomer()
Read more about transactions in the Java EE tutorial:
https://docs.oracle.com/javaee/7/tutorial/transactions003.htm
It is not necessary to mess with transaction management to achieve your requirement.
Your code should invoke javax.persistence.EntityManager.clear() before returning from your DAO. This will detach your entity bean from the persistence context, which will no longer track it. From the java doc:
Clear the persistence context, causing all managed entities to become detached. Changes made to entities that have not been flushed to the database will not be persisted.

JSP beans - Read the DB each time I load the page?

I have no code done yet but I'm thinking on how I'm supposed to do this in JSP/JSF.
So, I have some classes I was thinking I could load from a DB whenever the session starts. My first idea is that I just load them once with the necessary data from the DB, do all the operations, and then destroy the bean when the session is done. The problem is, what if another user changes information during the session? So I thought I could use a page scope, however I don't want to overload the server.
What's the best practice on this?
Firstly, each visitor to your app gets their own session-scoped bean, so you've only got to worry about persisting each user's changes to the data on the bean.
Secondly, you are worrying about matters which are taken into consideration by ORM offerings. Using the API provided by something like Spring JPA or Hibernate will present you with controls for persisting data changes back to the DB via a local handle on a Bean.
I decided to use an application scoped bean instead of a singleton class. That will do.

JPA: Extending the persistence context vs. detaching entities

There appear to be two patterns to implement business transactions that span several http requests with JPA:
entity-manager-per-request with detached entities
extended persistence context
What are the respective advantages of these patterns? When should which be preferred?
So far, I came up with:
an extended persistence context guarantees that object identity is equivalent to database identity, simplifying the programming model and potentially disspelling the need to implement equals for entities
detached entities require less memory than an extended persistence context, as the persistence context also has to store the previous state of the entity for change detection
no longer referenced detached entities become eligible for garbage collection; persistent objects must first be detached explicitly
However, not having any practical experience with JPA I am sure I have missed something of importance, hence this question.
In case it matters: We intend to use JPA 2.0 backed by Hibernate 3.6.
Edit: Our view technology is JSF 2.0, in an EJB 3.1 container, with CDI and possibly Seam 3.
Well, I can enumerate challenges with trying to use extended persistence contexts in a web environment. Some things also depend on what your view technology is and if it's binding entities or view level middlemen.
EntityManagers are not threadsafe.
You don't need one per user session.
You need one per user session per
browser tab.
When an exception comes out of an
EntityManager, it is considered
invalid and needs to be closed and
replaced. If you're planning to
write your own framework extensions
for managing the extended lifecycle,
the implementation of this needs to
be bullet proof. Generally in an
EM-per-request setup the exception
goes to some kind of error page and
then loading the next page creates a
new one anyway like it always would
have.
Object equality is not going to be
100% automagically safe. As above,
an exception may have invalidated
the context an object loaded earlier
was associated with, so one fetched
now will not be equal. Making that
assumption also assumes an extremely
high level of skill and
understanding of how JPA works and
what the EM does among the
developers using it. e.g.,
accidentally using merge when it
wasn't needed will return a new
object which will not satisfy ==
with its field-identical
predecessor. (treating merge like a
SQL 'update' is an extremely common
JPA noobie 'error' particularly
because it's just a no-op most of
the time so it slides past.)
If you're using a view technology
that binds POJOs (e.g., SpringMVC)
and you're planning to bind web form
data directly onto your Entities,
you'll get in trouble quick.
Changes to an attached entity will
become persistent on the next
flush/commit, regardless of whether
they were done in a transaction or
not. Common error is, web form
comes in and binds some invalid data
onto an entity, validation fails and
trys to return a screen to inform
user. Building error screen
involves running a query. Query
triggers flush/commit of persistence
context. Changes bound to attached
entity get flushed to database,
hopefully causing SQL exception, but
maybe just persisting corrupt data.
(Problem 4 can of course also happen with session per request if the programming is sloppy, but you're not forced to actively work hard at avoiding it.)

How to control JPA persistence in Wicket forms?

I'm building an application using JPA 2.0 (Hibernate implementation), Spring, and Wicket. Everything works, but I'm concerned that my form behaviour is based around side effects.
As a first step, I'm using the OpenEntityManagerInViewFilter. My domain objects are fetched by a LoadableDetachableModel which performs entityManager.find() in its load method. In my forms, I wrap a CompoundPropertyModel around this model to bind the data fields.
My concern is the form submit actions. Currently my form submits pass the result of form.getModelObject() into a service method annotated with #Transactional. Because the entity inside the model is still attached to the entity manager, the #Transactional annotation is sufficient to commit the changes.
This is fine, until I have multiple forms that operate on the same entity, each of which changes a subset of the fields. And yes, they may be accessed simultaneously. I've thought of a few options, but I'd like to know any ideas I've missed and recommendations on managing this for long-term maintainability:
Fragment my entity into sub-components corresponding to the edit forms, and create a master entity linking these together into a #OneToOne relationship. Causes an ugly table design, and makes it hard to change forms later.
Detach the entity immediately it's loaded by the LoadableDetachableModel, and manually merge the correct fields in the service layer. Hard to manage lazy loading, may need specialised versions of the model for each form to ensure correct sub-entities are loaded.
Clone the entity into a local copy when creating the model for the form, then manually merge the correct fields in the service layer. Requires implementation of a lot of copy constructors / clone methods.
Use Hibernate's dynamicUpdate option to only update changed fields of the entity. Causes non-standard JPA behaviour throughout the application. Not visible in the affected code, and causes a strong tie to Hibernate implementation.
EDIT
The obvious solution is to lock the entity (i.e. row) when you load it for form binding. This would ensure that the lock-owning request reads/binds/writes cleanly, with no concurrent writes taking place in the background. It's not ideal, so you'd need to weigh up the potential performance issues (level of concurrent writes).
Beyond that, assuming you're happy with "last write wins" on your property sub-groups, then Hibernate's 'dynamicUpdate' would seem like the most sensible solution, unless your thinking of switching ORMs anytime soon. I find it strange that JPA seemingly doesn't offer anything that allows you to only update the dirty fields, and find it likely that it will in the future.
Additional (my original answer)
Orthogonal to this is how to ensure you have a transaction open when when your Model loads an entity for form binding. The concern being that the entities properties are updated at that point and outside of transaction this leaves a JPA entity in an uncertain state.
The obvious answer, as Adrian says in his comment, is to use a traditional transaction-per-request filter. This guarantees that all operations within the request occur in single transaction. It will, however, definitely use a DB connection on every request.
There's a more elegant solution, with code, here. The technique is to lazily instantiate the entitymanager and begin the transaction only when required (i.e. when the first EntityModel.getObject() call happens). If there is a transaction open at the end of the request cycle, it is committed. The benefit of this is that there are never any wasted DB connections.
The implementation given uses the wicket RequestCycle object (note this is slightly different in v1.5 onwards), but the whole implementation is in fact fairly general, so and you could use it (for example) outwith wicket via a servlet Filter.
After some experiments I've come up with an answer. Thanks to #artbristol, who pointed me in the right direction.
I have set a rule in my architecture: DAO save methods must only be called to save detached entities. If the entity is attached, the DAO throws an IllegalStateException. This helped track down any code that was modifying entities outside a transaction.
Next, I modified my LoadableDetachableModel to have two variants. The classic variant, for use in read-only data views, returns the entity from JPA, which will support lazy loading. The second variant, for use in form binding, uses Dozer to create a local copy.
I have extended my base DAO to have two save variants. One saves the entire object using merge, and the other uses Apache Beanutils to copy a list of properties.
This at least avoids repetitive code. The downsides are the requirement to configure Dozer so that it doesn't pull in the entire database by following lazy loaded references, and having yet more code that refers to properties by name, throwing away type safety.

merging / re-attaching IN JPA / Hibernate without updating the DB

Working with JPA / Hibernate in an OSIV Web environment is driving me mad ;)
Following scenario: I have an entity A that is loaded via JPA and has a collection of B entities. Those B entities have a required field.
When the user adds a new B to A by pressing a link in the webapp, that required field is not set (since there is no sensible default value).
Upon the next http request, the OSIV filter tries to merge the A entity, but this fails as Hibernate complains that the new B has a required field is not set.
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value
Reading the JPA spec, i see no sign that those checks are required in the merge phase (i have no transaction active)
I can't keep the collection of B's outside of A and only add them to A when the user presses 'save' (aka entitymanager.persist()) as the place where the save button is does not know about the B's, only about A.
Also A and B are only examples, i have similar stuff all over the place ..
Any ideas? Do other JPA implementaions behave the same here?
Thanks in advance.
I did a lot reading and testing. The problem come from my misunderstanding of JPA / Hibernate. merge() always does a hit on the DB and also schedules an update for the entity. I did not find any mention of this in the JPA spec, but the 'Java Persistence with Hibernate' book does mention it.
Looking through the EntityManager (and Session as fallback) API it looks as if there is no means of just assigning an entity to the current persistent context WITHOUT scheduling an update. After all, what I want is to navigate the object graph, changing properties as needed and trigger an update (with version check if needed) later on. Something i think every Webapp out there using ORM must do?
The basic workflow i 'm looking for:
load an entity from the DB (or create a new one)
let the entity (and all its associations become detached (as the EntitManager closes at the end of a HTTP request)
when the next HTTP request comes in, work again with those objects, navigating the tree without fear of LazyInitExceptions
call a method that persists all changes made during 1-3)
With the OSIV filter from spring in conjunction with an IModel implementation from wicket i thought i have archived this.
I basically see 2 possible ways out of it:
a) load the entity and all the associations needed when entering a certain page (use case), letting them become detached, adding/ changing them as needed in the course of several http requests. Than reattach them when the user initiates a save (validators will ensure a valid state) and submit them to the database.
b) use the current setup, but make sure that all newly added entities have all their required fields set (probably using some wizard components). i would still have all the updates to the database for every merge(), but hopefully the database admin won't realize ;)
How do other people work with JPA in a web environment? Any other options for me?

Categories