JPA, removing an entity which has found by different manager - java

Assume we have a simple entity bean, like above
#Entity
public class Schemes implements serializable{
...
#Id private long id;
...
}
I find a record using find method and it works perfect, the problem is I cannot manipulate it(remove) by another EntityManager later, for example I find it with a method, and later I want to remove it, what is the problem?! if I find it with same manager again I would remove it, but if object has found by another manager I cannot.
#ManagedBean #SessionScopped class JSFBean {
private Schemes s;
public JSFBean(){
....
EntityManager em;//.....
s=em.find(Schemes.class,0x10L);//okay!
....
}
public void remove(){//later
....
EntityManager em;//.....
em.getTransaction().begin();
em.remove(s);//Error! some weird error, it throws IllegalArgumentException!
em.getTransaction().commit();
....
}
}
many thanks.

You are probably getting a java.lang.IllegalArgumentException: Removing a detached instance.
The two EMs do not share a persistence context and for the second EM, your object is considered detached. Trying to remove a detached object will result in an IllegalArgumentException.
You can refetch the entity before the removal:
Schemes originalS = em.find(Schemes.class, s.getId());
em.remove(originalS);
EDIT You can also delete the entity without fetching it first by using parametrized bulk queries:
DELETE FROM Schemes s WHERE s.id = :id
Be aware that bulk queries can cause problems on their own. First, they bypass the persistence context, meaning that whatever you do with a bulk query will not be reflected by the objects in the persistence context. This is less an issue for delete queries than for update queries. Secondly, if you have defined any cascading rules on your entites - they will be ignored by a bulk query.

Related

JPA flushing to Database before #PreUpdate is called

I am trying to capture the entity data in the database before the save is executed, for the purpose of creating a shadow copy.
I have implemented the following EntityListener in my Spring application:
public class CmsListener {
public CmsListener() {
}
#PreUpdate
private void createShadow(CmsModel entity) {
EntityManager em = BeanUtility.getBean(EntityManager.class);
CmsModel p = em.find(entity.getClass(), entity.getId());
System.out.println(entity);
}
}
The entity does indeed contain the entity object that is to be saved, and then I inject the EntityManager using another tool, which works fine - but for some reason, the entity has already been saved to the database. The output of CmsModel p = em.find(...) results in identical data which is in entity.
Why is JPA/hibernate persisting the changes before #PreUpdate is called? How can I prevent that?
I would assume this is because em.find doesn't actually query the database but fetches the object from cache, so it actually fetches the same object entity refers to (with changes already applied).
You could check your database log for the query that fetches the data for entity.id to verify this is indeed the case or you could add a breakpoint in createShadow() and have a look at the database entry for entity at the time the function is called to see for yourself if the changes are already applied to the database at that time.
To actually solve your problem and get your shadow copy you could fetch the object directly from database via native query.
Here is an untested example of what this could look like:
public CmsModel fetchCmsModelDirectly(){
Query q = em.createNativeQuery("SELECT cm.id,cm.value_a,cm.value_b FROM CmsModel cm", CmsModel.class);
try{
return q.getSingleResult();
}catch(NoResultException e){
return null;
}
}
Do you check if the entity is really updated to database? My suspect is that the change is only updated to the persistence context (cache). And when the entity is query back at the listener, the one from the cache is returned. So they are identical.
This is the default behavior of most of the ORM (JPA in this case) to speed up the data lookup. The ORM framework will take care of the synchronizing between the persistence context and the database. Usually when the transaction is committed.

touch equivalent for Hibernate entity

I'd like to implement repository method void touch(MyEntity myEntity) which enforces SQL call of update of entity columns to their current values. (The reason behind is the on update trigger which needs to be invoked in some point of execution.) Ideal usecase is:
void serviceMethod(Long myEntityId) {
MyEntity myEntity = myEntityRepository.findOne(myEntityId);
...
myEntityRepository.touch(myEntity);
...
}
There are already similar questions on SO which don't work for me: Force update in Hibernate (my entity is detached), Implementing “touch” on JPA entity? (doing some harmless change works but is not general and has bad impact on code readability), Hibernate Idempotent Update (similar example).
I am aware of session interceptor method findDirty and also CustomEntityDirtinessStrategy both described in this Vlad Mihalcea's article. However, it seems to use findDirty I would have to override session interceptor, which is not possible from within repository method since the interceptor is final field assigned to session at session creation. And CustomEntityDirtinessStrategy comes from SessionFactory which is global. I rather need some one-shot solution to temporary consider one concrete entity of one concrete class dirty.
The so-far-best working solution is to set invalid (array of nulls) entity snapshot into persistence context, so that the subsequent logic in flush() evaluates entity as differing from snapshot and enforce update. This works:
#Override
#Transactional
public void touch(final T entity) {
SessionImpl session = (SessionImpl)em.getDelegate();
session.update(entity);
StatefulPersistenceContext pctx = (StatefulPersistenceContext) session.getPersistenceContext();
Serializable id = session.getIdentifier(entity);
EntityPersister persister = session.getEntityPersister(null, entity);
EntityKey entityKey = session.generateEntityKey(id, persister);
int length = persister.getPropertyNames().length;
Field entitySnapshotsByKeyField = FieldUtils.getField(pctx.getClass(), "entitySnapshotsByKey", true);
Map<EntityKey,Object> entitySnapshotsByKey = (Map<EntityKey,Object>)ReflectionUtils.getField(entitySnapshotsByKeyField, pctx);
entitySnapshotsByKey.put(entityKey, new Object[length]);
session.flush();
em.refresh(entity);
}
The advice in Force update in Hibernate didn't work for me because session.evict(entity) clears entitySnapshotsByKey entry at all, which causes subsequent org.hibernate.event.internal.DefaultFlushEntityEventListener#getDatabaseSnapshot loads fresh entity from db. The question is 9 years old and I'm not sure if it's applicable to current version of Hibernate (mine is 5.2.17).
I am not satisfied with such hacky solution though. Is there some straightforward way or something I could do simpler?

How to work with "long living entities" or "longer living persistence context"?

I am currently working on a medium sized, desktop-based administration and configuration tool implemented in Java using JavaFx, google-guice, and hibernate for its jpa implementation.
Until now i got away with a single EntityManager injected as a #Singleton. Meaning that i had this EntityManager "open" from start to shutdown. All loaded entites were permanently known in the context and I barely had any problems with this approach. Although i know/believe it is not the best solution (but easy and a I had no time to redesign the application).
Now the application gets extended and I have to use multiple persistence units simultaneously.
I could try to get my current singleton-approach working with using something like:
#Inject
#PersistenceContext(name="JPA-Unit1")
#Singleton
private EntityManager em;
It never felt perfect, but that feels "ugly". And since I had severe problems getting multiple persistence contexts working with guice, I had to do a lot of reasearch on this topic.
And i came across several blogs SO-questions either mentioning that an instance of the EntityManager should only live as long it is needed or some extended persistence contexts.
Since I useJavaFx in place I use the *Property classes to bind the data directly into the UI.
Simplified user entity (property-based access):
#Entity
#Table(name = "USERS")
#NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
public class User implements Serializable {
[...]
private final SimpleStringProperty loginProperty = new SimpleStringProperty();
public User() {
}
public String getLogin() {
return this.loginProperty.get();
}
public void setLogin(String login) {
this.loginProperty.set(login);
}
public SimpleStringProperty loginProperty() {
return this.loginProperty;
}
[...]
}
If i start editing the user data in the UI it gets directly updated in the entity:
this.login.textProperty().bindBidirectional(user.loginProperty());
There is no need for extensive "business logic". It gets all handled via (input) validation. If all input is valid i simply save the data via
userService.update(user);
Parts of the UserService (exactly: its abstract super-class):
public abstract class AbstractService<PK extends Serializable, Type> implements GenericService<PK, Type> {
protected Class<Type> clazz;
#PersistenceContext(name = "JPA-Unit1")
#Inject
protected Provider<EntityManager> emProvider;
public AbstractService(Class<Type> clazz) {
this.clazz = clazz;
}
#Transactional
#Override
public Type create(Type entity) {
this.emProvider.get().persist(entity);
return entity;
}
#Transactional
#Override
public Type update(Type entity) {
this.emProvider.get().persist(entity);
return entity;
}
}
As you can see: the service class is pretty straightforward. I could even delete all this "service"-classes and directly use the entitymanager directly in my UI controller.
In this service you can see the "problem" the user i edit got loaded earlier by its named query and put into a list. The loading is also done in a #Transactional method.
But everytime i call this.emProvider.get() I get a new instance with an empty context. And if I want to save the previously edited user I have the problem that persist actually performs an insert (I assume because it is not known in the context [detached]) which leads to an PK-constraint violation or if I delete (null) its ID-property there is a new user row inserted.
My actual questions are:
1. Is this approach "OK"? If yes what do I do with this "always" new persistence context? Call contains and merge every single time?
Should I get rid of my service class and implement the persistence operations directly in my UI-controller?
Can I do an this.emProvider.get() once the User-UI-controller got loaded and use it the entire life time of the application?
Something totally different?
My understanding is that your app uses Guice Persist.
The answer to this question depends on your use cases; however, you absolutely need to realize one thing:
For as long as an EntityManager is open, its underlying persistence context tracks every single change to each persistent entity.
This means that if you keep an entity manager open for the duration of the application, whenever you call e.g. User.setLogin(), the change you just made is already regarded as persistent. Now, moving to your update method, calling persist on an entity that is already managed has no effect; however, since you're calling it from a #Transactional method, Guice wraps the call in a transaction, and consequently, all the changes are are being flushed to the database once the method ends.
This means that if you modify multiple entities at once within your app, and then call AbstractService.update on one of them, you will actually be saving all the changes your app has done to other entities in the meantime, even if AbstractService.update has not been called on them explicitly.
Using the entity manager-per-transaction approach is indeed much safer. Between transactions, there will be no open persistence context, and as a result all the entities will become detached, which will prevent any updates on them from accidentally being flushed to the database.
However, for the same reason, your update method will need to call em.merge on the entity you want to update in the database. merge is basically telling the entity manager 'please put this entity back into the persistence context, and make it have the exact state that the provided entity has'. Calling persist makes it look as though it was a new entity, and PK-constraint violations will indeed follow.

merge vs find to update entities JPA

From the book Pro EJB3 JPA:
The most common strategy to handle this (-update entities-) in Java EE application that uses JPA is to place the results of the changes into detached entity instances and merge the pending changes into a persistence context so that they can be written to the database
Example:
The emp param is a detached entity
#Stateless
public class EmployeeServiceBean {
#PersistenceContext
EmtityManager em;
public void updateEmployee(Employee emp){
if(em.find(Employee.class, emp.getId()) == null){
throw new IllegalArgumentException("Unknown Employee id")
}
em.merge(emp);
}
}
Then, says:
If the amount of information being udated is very small, we can avoid the detached object and merge() operation entirely by locating the managed version and manually copying the changes into it.
Example:
Here the emp is attached
public void updateEmployee(int id, String newName, long newSalary) {
Employee emp = em.find(Employee.class, id);
if(emp==null){
throw new IllegalArgumentException("Unknown Employee id")
}
emp.setEmpName(newName);
emp.setSalary(newSalary);
}
So, looks like for small updates and create operations the strategy find() and then set new values one by one is convenient. But!, for big updates of data (i.e collections) is preferred have a detached entity and all it's relations (with CascadeType.Merge) and do a big merge().
OK, but why?
Because if your bean has a lot of attributes, JPA will check one by one in the merge process, for all attributes, if you're dealing with a detached object.
Now, if you have a bean with 200 atrributes and want to change only 1 field, it´s easier for JPA to just get the managed version (internally, JPA knows when one field of a managed entity is "dirty" or not), then it will only deal with that specific attribute.

Inserting the record into Database through JPA

In my code I am using JSF - Front end , EJB-Middile Tier and JPA connect to DB.Calling the EJB using the Webservices.Using MySQL as DAtabase.
I have created the Voter table in which I need to insert the record.
I ma passing the values from the JSF to EJB, it is working.I have created JPA controller class (which automatcally generates the persistence code based on the data base classes)
Ex: getting the entity manager etc.,
em = getEntityManager();
em.getTransaction().begin();
em.persist(voter);
em.getTransaction().commit();
I have created the named query also:
#NamedQuery(name = "Voter.insertRecord", query = "INSERT INTO Voter v
values v.voterID = :voterID,v.password = :password,v.partSSN = :partSSN,
v.address = :address, v.zipCode = :zipCode,v.ssn = :ssn,
v.vFirstName = :vFirstName,v.vLastName = :vLastName,v.dob = :dob"),
But still not able to insert the record?
Can anyone help me in inserting the record into the Data base through JPA.(Persistence object)?
Update:
If we are using the container managed entity manager, should we need to write begin and commit transactions again...
like this:
em.getTransaction().begin();
em.getTransaction().commit();
I have written:
Voter v= new Voter(voterID,password,partSSN,address,zipCode,ssn,vFirstName,vLastName,d1,voterFlag);
em.persist(v);
But it is resulting to Null pointer exception.
SEVERE: java.lang.NullPointerException
at ejb.Registration.reg(Registration.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1052)
at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1124)
at com.sun.ejb.containers.BaseContainer.invokeTargetBeanMethod(BaseContainer.java:4038)
at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5223)
I think that you missed the point of JPA. With JPA, you're not supposed to write queries to insert, update or delete persistent objects, JPA will generate them for you.
So, what you need to do is to create domain objects and to annotate them to make them "persistable" (such annotated objects are called entities) and tell the JPA engine how to "map" them to your database. Let me try to show you the right path...
First, create a Voter domain object and add JPA annotations (an entity class must be annotated with the Entity annotation, must have a no-arg constructor, must implement Serializable, must have a primary key identified by the Id annotation):
#Entity
public class Voter implements Serializable {
private Long id;
private String firstName;
private String lastName;
private String password;
// other attributes
// No-arg constructor
public Voter() {}
#Id #GeneratedValue // property access is used
public Long getId() { return this.id; }
protected void setId(Long id) { this.id = id; }
// other getters, setters, equals, hashCode
}
I'm using JPA's defaults here (default table name, column name, etc). But this can be customized using the Table or Column annotations if you need to map your entity to an existing model.
Then, create a new instance and set the various attributes:
Voter voter = new Voter();
voter.setFirstName(firstName);
voter.setLastName(lastName);
...
And persist it:
em.getTransaction().begin();
em.persist(voter);
em.getTransaction().commit();
This is just a short introduction, JPA can't be covered in one answer. To go further, I suggest to check the Introduction to the Java Persistence API from the Java EE 5 Tutorial.
Update: In a managed component, for example an EJB, the EntityManager is typically injected and transactions are managed by the container (i.e. you don't explicitly call begin/commit). In your case, my bet is that the EntityManager isn't successfully injected and calling any method on it results in a NPE. But that's just a guess, you need to provide more details. What is the line 39 of your EJB? How is the EntityManager annotated? What does your persistence.xml looks like? Please update your question with the relevant details.
Also, you dont need to write begin and commit transactions again.Like this :
em.getTransaction().begin();
em.getTransaction().commit();
if only you are using container managed Entity Managers because it is automatically done by the container.
I guess it is not retrieving the values of from the parameters inserted in the constructor which leads to a NullPointerExpception. It is better if you use voter.setPassword(password); for example to pass in values into the Voter entity. Also check if the values are empty.
Pascal is right you can do it that way. If you want to use the named queries you can do it like this:
Write a method that takes the value(s) to be set and use this.
Query q = em.createNamedQuery("NamedQueryXYZ").setParameter("parameter name", valueToSet)
Parameter name would be using your example "password" or "attribute" basically whatever follows the colon.
I am fairly new to JPA, JSF and all that jazz but I hope this helps.
if you re using the entity manager means you re handling transaction with JTA, so the entity manager will be handled by the container, you re not be able to use
em.getTransaction().begin();
em.getTransaction().commit();
em.getTransaction() it s an entity transaction which will be handled by JTA .
You ll need to directly use the persist(), as you have the entitymanager, and you re data will be addedd.
If you want to use the query it s always possible in a a en.createQuery ...
But I don t know if it can be use as a named query.

Categories

Resources