Refreshing entity instance after using merge in hibernate? - java

am using hibernate merge method, to deal with detached instance from entity, and i thought that the return of this method will be a new fetched instance from database as hibernate saveOrUpdate method, but that wasn't the case, and i think it's logic as it's a detached instance, so is there a better way to return the new instance rather than using findById,
regards,

The merge method copies the state of the passed object to a persistent entity with the same identifier (that is either already associated with the session or will be loaded) and then return a reference to that persistent entity. The object passed as parameter is not attached to the session.
So unless I didn't understand the question, I think you should do something like this:
Foo mergedFoo = session.merge(foo);

Related

Simple Hibernate/JPA query returning proxy objects

I am using Hibernate 5 & Spring Data.
Inside my PartyDao, I have the following method:
#Query("from Party where id in :partyIDs")
List<PartyTO> loadByIDs(#Param("partyIDs") List<Long> partyIDs);
I am calling it like this:
partyList = partyDao.loadByIDs(userPartyIDsList));
but I am getting a list of Hibernate proxy objects (with all the fields set to null and a handler field of type org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer).
This makes no sense to me! Why is Hibernate not loading the objects FROM the query root I am specifying?
I changed it to:
#Query("select party from Party party where party.id in :partyIDs")
List<PartyTO> loadByIDs(#Param("partyIDs") List<Long> partyIDs);
to try to make it more explicit that that I want this object fetched, but it's still returning the proxy objects. Is there something I'm missing? I don't know how I would make it fetch itself.
EDIT:
The proxy object actually has an attribute called target, which has all the attributes set. Why are they not placed into the object itself?
I am not getting a "lazy initialization exception", but a NullPointerException inside a Comparator that is sorting the parties by name:
...
return o1.name.compareTo(o2.name);
The problem is your direct access to the name property of your object.
...
return o1.name.compareTo(o2.name);
Hibernate will always return proxy objects, and the serialization of some more complex structures might lead you to issues in the future including the lazy instantiation exceptions mentioned. However, the cause of your problem is direct access of a property, if you correctly utilize your getter functions within your comparators you will not have any other problem.
The proxy object is a runtime extension of your target class, it will have the same interface as the target class, but in true OOD fashion the internals are not visible or accessible. The only guarantee is the interface contract presented, and that is what you should be coding against regardless within your objects.
Change your comparator and other code to match the following, and you won't have this issue again.
...
return o1.getName().compareTo(o2.getName());
The value will be read into the main object by calling the property method instead of the attribute itself.
The Comparator return statement must be changed to:
return o1.getName().compareTo(o2.getName());

Automatically assigning value to transient attribute

I am using #Entity from javax.persistence.Entity to create my entities and in this particular case I had to create a transient attribute (private Boolean assigned;) and I am using PagingAndSortingRepository from org.springframework.data.repository to create interfaces to manage my database entities.
I need to assign this value (Boolean assigned) when a List (OneToMany) attribute is empty, so I am doing it programatically using an if clause, the problem is I have to write that if clause everywhere and I would like to know if it is possible to auto-assign that variable somehow.
Thanks in advance.
If you need to set the value of this flag before being persisted in the database, I would recommend use entity listener #PrePersist, basicallu give you the possibility to execute certain logic before you persist the object, in the method you could check if the Array is empty and set the value to false.
There are other events such as:
#PostLoad Executed after an entity has been loaded into the current
persistence context or an entity has been refreshed.
#PostLoad
public void setAssigned() {
//Your logic for set to true or false the transient variable.
}
I think this is one option to do the logic in only one place at be managed by the provider. Read more about it here

is it necessary to return a different object from the getter method than the object passed by Hibernate to the setter?

I recently came accross the following statement on Java persistence with Hibernate book.I was able to understand everything else except the highlighted one.
Another issue to consider is dirty checking. Hibernate automatically detects
object state changes in order to synchronize the updated state with the database.
It’s usually safe to return a different object from the getter method than the
object passed by Hibernate to the setter. Hibernate compares the objects by
value—not by object identity—to determine whether the property’s persistent
state needs to be updated. For example, the following getter method doesn’t
result in unnecessary SQL UPDATEs:
public String getFirstname() {
return new String(firstname);
}
Query: My concern here is we are creating new instance. Is that really necessary? kindly correct me if i'm wrong here..
If you will return different object from getter this means you are trying to create a defensive copy.
From hibernate perspective if you return different object from getter that object will have no history with hibernate session, and if you will call save on that object and that object already exist in database you will have ConstraintViolationException, you have to call saveOrUpdate instead. Call to saveOrUpdate will cause hibernate to issue select statement to database before committing.
if some object was already in session and you call commit after performing some changes Hibernate will issue update query

Java/Hibernate: How to detect, if field is lazy-loaded proxy and not actual data?

I'm converting my entity to DTO and I want to set NULL as DTO value for all fields, which are lazy-loaded and not initialized (because I do not want to transfer all the data all the time).
I've tried:
if (!(entity.getNationality() instanceof HibernateProxy))
this.setNationalityFromEntity(entity.getNationality());
But it did not seemed to help.
Any suggestions are welcome!
Thank you!
They way we do this in our Entities is we have boolean methods which do the check in a way that will not trigger the lazy loading. For example, if our Entity had an associated entity called 'associatedSomething', then the method to check if that associated Entity has been lazy loaded would be:
public boolean isAssociatedSomethingLoaded() {
if (associatedSomething instanceof HibernateProxy) {
if (((HibernateProxy)associatedSomething).getHibernateLazyInitializer().isUninitialized()) {
return false;
}
}
return (getAssociatedSomething() != null);
}
NOTE: It's important not to use getAssociatedSomething() in the check, as this makes sure that the associated Entity does not get lazy-loaded during the check.
The class is always a proxy, whether it's initialized or not, so you're going to exclude it every time if you just check for instances of proxy. The Lazy Load does not cause the Proxy reference on the entity to be replaced with a reference to a new object, it just populates the fields.
To find out if it's actually initialized you need to ask it!
if (HibernateProxy.class.isInstance(entity.getNationality())) {
HibernateProxy proxy = HibernateProxy.class.cast(entity.getNationality());
if (!proxy.getHibernateLazyInitializer().isUninitialized()) {
this.setNationalityFromEntity(entity.getNationality());
}
}
The mere possibility of being able to invoke a getter for some state that shouldn't be available for a use case is problematic in my opinion, but that's a different story. I would suggest you implement a proper DTO approach instead to avoid accidental errors.
I created Blaze-Persistence Entity Views for exactly that use case. You essentially define DTOs for JPA entities as interfaces and apply them on a query. It supports mapping nested DTOs, collection etc., essentially everything you'd expect and on top of that, it will improve your query performance as it will generate queries fetching just the data that you actually require for the DTOs.
The entity views for your example could look like this
#EntityView(Person.class)
interface PersonDto {
String getNationality();
}
Querying could look like this
List<PersonDto> dtos = entityViewManager.applySetting(
EntityViewSetting.create(PersonDto.class),
criteriaBuilderFactory.create(em, Person.class)
).getResultList();

Hibernate saveOrUpdate behavior

Does anyone know how Hibernate knows whether to INSERT or to UPDATE a value in the database when session.saveOrUpdate() is called?
So far, I have only determined that it is not dependent on the information in the cache, and that the existence of the entity in the database is determined by the primary key.
When you use .saveOrUpdate() Hibernate will check if the object is transient (it has no identifier property) and if so it will make it persistent by generating it the identifier and assigning it to session. If the object has an identifier already it will perform .update().
From the documentation:
saveOrUpdate() does the following:
if the object is already persistent
in this session, do nothing
if another object associated with the
session has the same identifier,
throw an exception
if the object has no identifier
property, save() it
if the object's identifier has the
value assigned to a newly
instantiated object, save() it
if the object is versioned by a
"version" or "timestamp", and the
version property value is the same
value assigned to a newly
instantiated object, save() it
otherwise update() the object
Perhaps it is helpful to quote the Hibernate bible (Java Persistence with Hibernate, 2nd ed., page 528):
More experienced Hibernate users use saveOrUpdate() exclusively; it's much easier to let Hibernate decide what is new and what is old, especially in a more complex network of objects with mixed state. The only (not really serious) disadvantage of exclusive saveOrUpdate() is that it sometimes can't guess whether an instance is old or new without firing a SELECT at the database - for example, when a class is mapped with a natural composite key and no version or timestamp property.
How does Hibernate detect which instances are old and which are new? A range of options is available. Hibernate assumes that an instance is an unsaved transient instance if:
The identifier property is null.
The version or timestamp property (if it exists) is null.
A new instance of the same persistent class, created by Hibernate internally, has the same database identifier values as the given instance.
You supply an unsaved-value in the mapping document for the class, and the value of the identifier property matches. The unsaved-value attribute is also available for version and timestamp mapping elements.
Entity data with the same identifier value isn't in the second-level cache.
You supply an implementation or org.hibernate.Interceptor and return Boolean.TRUE from Interceptor.isUnsaved() after checking the instance in your code.
As stated here, saveOrUpdate either saves a transient instance by generating a new identifier or updates/reattaches the detached instances associated with its current identifier. More specifically it does:
if the object is already persistent in this session, do nothing
if another object associated with the session has the same identifier, throw an exception
if the object has no identifier property, save() it
if the object's identifier has the value assigned to a newly instantiated object, save() it
if the object is versioned by a <version> or <timestamp>, and the version property value is
the same value assigned to a newly instantiated object, save() it
otherwise update() the object
This is done based on the value of the primary key. If the primary key is undefined, it's value will default to 0 for numeric surrogate keys and save will be performed. If the primary key is filled out, it will invoke an update.
If someone not really understood in theory then there is a code
MyModel sent = myDao.myDaoImpl(id);
if(sent == null){
sent = **new MyModel();** // new Object
sent.setXX(id);
sent.setYY("Yes");
sent.setDate(new Date());
myDao.saveOrUpdate(sent); // Insert will be called
} else if(! "Yes".equalsIgnoreCase(sent.getFlag())) {
sent.setXX("Yes");
sent.setDate(new Date());
myDao.saveOrUpdate(sent); // Update will be called
}

Categories

Resources