I am trying understand the Vaadin Java EE app example at https://github.com/peterl1084/cdiexample, and I have some questions regarding the persistence part of the example.
the example uses persist for new entities and merge for existing entities. Why is it necessary to use two different methods?
I’ve used JPA in a standalone Java application and then I use getTransaction().begin() and getTransaction().commit() from the EntityManager. The example does not contain transactions. Are transaction handled by the container?
removal of the customer in the example goes as follows:
customer = entityManager.getReference(Customer.class, customer.getId());
entityManager.remove(customer);
Why is it necessary to first get the reference?
Yes, the container manages the transactions. The benefit of container managed transactions is, that it will automaticaly take care of things such as rollbacks. If you have multiple entities that you want to save within the same transaction, then you can annotate your method with @Transactional, which begins a new transaction when that method is being called (this is a simplified example, it might also use an existing transaction, if one is available. See documentation for more details).
Entity uses optimistic locking. If someone else has modified the entity after you fetched it, then trying to remove the entity causes an OptimisticLockingException. By fetching the most current instance, we make sure that the entity gets deleted regardless if someone else has modified it.
Thanks for the url. I’ve read it, along with a few others.
I still have a couple of questions remaining:
the example code uses persist for new objects and merge for updating existing objects. I understand that using persist for creating objects is the most efficient way since it does not a select before doing an insert. However, the merge could also do object creation in the database, however with a select preceding an insert/update. Is this the reason why the code choses to differentiate between persist and merge for saving objects? Or does it has to do with the idea that objects in the entity manager are only valid within a single Vaadin session, and therefore are brought into the persistence context by using merge?
my code has two classes which are related with bi-directional relationships, say Person and Department. Now, departments are created on beforehand. Then, over time, persons are added, as well as their relationship with departments. Now, if I create a person, it would be stored with persist (since it is a new object). However, the department already exists. Does this mean that I have to persist the person and merge the department to properly store the bi-directional relationship? I suppose the cascade option in JPA does not work here, since the person should use persist whereas the department object should use merge.
Hey J G. I suppose I’m the guy you can blame for the code example
It’s been (according to Github) already a year that code was committed but I’m remembering that the initial intent with separated persist and merge was that when ‘merging’ already persisted entity, calling the storeCustomer is better protecting the passed entity. This is because as Kim pointed out in his Stackoverflow link, by having an entity merged the EntityManager will make the NEW copy of passed object managed while the existing object will no longer be managed.
What this means is that if you do other changes to customer entity after calling storeCustomer (in some other EJB within the same transaction) you could change the state of the customer entity without the CustomerServiceBean noticing. Once the EJB call chain would end the changes (done for customer entity after calling storeCustomer) would be flushed to database. By having storeCustomer call merge it will make a new copy of passed customer object but will not return it. This way any additional changes to given customer object will NOT be stored to DB. This is of course question of taste if changing the state of the customer after calling storeCustomer is ok or not but my intent was to protect the customer entity from this kind of (outside of service) manipulation. Because the example is so simplistic this might not be evident by looking at the code.
In general the first invocation to EJB method starts a transaction that will propagate over all EJB calls all the way to database layer. To achieve this the container managed transactions must be used and the datasource used for db-connectivity must support JTA. In the example this is defined in the persistence.xml. Also, the EntityManager must be injected with @PersistenceContext. By doing it this way you never have to take care of transaction management by your self. You can also change how transactions are handled by giving @TransactionalAttribute for the EJB method where you can say if you want the call always to create new transaction or participate in existing one.
This also means that if inside your EJB you reference another EJB with @EJB annotation, invocation to this other EJB will also be within the same transaction. Eventually when the call to first EJB returns all the changes will be flushed to DB (or rolled back in case of an exception). Thats how you can consistently change your db state from multiple different EJBs within one transaction. This is also why in general the Customer entity was merged, so that the managed instance is not leaked outiside of the CustomerServiceBean so that no other EJB could modify it accidentally.
Regarding your question about bi-directional relationships these you have to manage always by your self. One option how adding Persons to Department would be simple is that Person would know the department into which it belongs and the Department would have mappedBy=“department” for the Person where department is a property in Person ponting to the Department. This way when you store persons in the Person db-table you would have a column for department’s id in Person table telling to which Department the Person belongs. This way you wouldn’t have to merge departments after every change and you wouldn’t have extra “person_to_department” middle table in between.
Regarding your question about removing a Customer and why it first fetches reference to the entity is again the same reason, the passed entity is not managed (as it might come from some Vaadin component into which it was fetched in another EJB call and then detached from EntityManger) and you can only remove a managed entity, hence first getting the reference to a managed entity and then calling remove for that will only work.
For my understanding: what is the lifetime of the EJB? Is this e.g. the Vaadinn request or session?
And which call(s) trigger the transaction and commiting the transaction? Is this a single persist/merge operation?
Lifetime of EJB is no way related to Vaadin. EBJs are deployed and running in EJB container. If you have @Stateless EJB there are several instances of an EJB co-existing in the container. If there are multiple invocations to EJB’s interface from various different clients the EJB container will assign one EJB to handle one request. If again EJB is @Stateful it means that the same EJB will handle all the requests from the same client allowing a conversational state to be maintained. There’s also something called @Singleton EJB which is single instance per EJB container.
From Vaadin’s point of view you acquire an EJB proxy reference by saying @EJB in your Vaadin CDI managed bean. What you get is a proxy reference and the container will under the hood find the actual implementing bean instance for you.
The transaction is started automatically by the EJB container when the first call from Vaadin goes to EJB. The transaction will end when this same call returns. All the possible other calls the EJB will do to another EJB is part of the same transaction by default unless transactionality attribute is switched by the annotation in the EJB bean or method.
for example in your Vaadin’s customer view you have a CDI container managed bean, which means that if you have some injection annotations in it, such as @Inject or @EJB they get automatically populated by the proxy object looked up from the container. When you call a method from the proxy this will invoke the EJB in the EJB container and during the process will begin the transaction. When your call to the proxy method (from Vaadin view) ends, the transaction is committed (or rolled back).