I know what is DTO: An object that carries data between processes in order to reduce the number of method calls.
and I know what is lazy-loading in hibernate.
I read this sentences in "Full Stack Development with JHipster" book :
JHipster uses DTO (Data Transfer Object) and VM (View Model) on the server side. DTOs are for transferring data from the service layer to and from the resource layer. They break the Hibernate transactions and avoids further lazy loading from being triggered by the resource layer.
I don't understand the relationship between DTO and lazy loading.
Lazy loading is for entities, not DTOs.
A JPA entity can be represented as a POJO or a Proxy.
Using EntityManager.find gives you a POJO:
Post post = entityManager.find(Post.class, postId);
While the EtityManager.getReference method gives you a Proxy:
Post post = entityManager.getReference(Post.class, postId);
The POJO has its basic properties initialized because a SELECT statement was executed to fetch the entity. The Proxy does not hit the database upon creation. Only the id is set based on the provided entity identifier. Only you access the Proxy properties, a SELECT statement will be executed.
Proxies are also used for collections (e.g. #OneToMany or #ManyToMany) which are using the FetchType.LAZY strategy by default. Once you access the LAZY collection, a SELECT statement will be executed to fetch the associated collection.
Now, a DTO is based on a projection, hence a SELECT statement is executed prior to populating the DTO. For this purpose, you can say that the DTO is eagerly loaded every time.
DTOs are much more efficient than entities for read-only projections because you load just the table columns that you explicitly requested.
If you pass Hibernate managed persistent entities to the resource layer with LazyLoading enabled, the resource layer will invoke get-methods in order to read their properties some of which are possibly not initialized at that time. Hibernate will then lazily load the data of that particular property from the persisntet store, sending an SQL statement (possibly each time starting and committing a new transaction) and waiting for response which is quite slow. If this happens hundred of times, each time having to initialize another property, each time triggering a lazy load, the user has to wait...
If you prepare a DTO in your service layer, containing all the data relevant to the resource layer, read access to that DTO is highly efficient without the risk of hitting the database for any get-method invokation as everything relevant is in memory already. No subsequent lazy load will be triggered.
In Simple terms: If you call getter of a lazy loading marked field, Hibernate will make a db query for that data.
This is one of the reasons you should not return Entities as backend response... any JSON conversion(Serialization)/getter call will trigger unwanted loading of the data.
whereas a DTO is made specifically to transfer data as per use and you create DTO from these Entities (Multiple DTO can be created from one Entity) and pick only required data fields
Eg.
User entity: has user details and list of friends
UserDetailsDTO: would only require the details and dont need 1000's of friends mapped to the user... and their friends...
UserFriendsDTO: we can selectively get the friends names or ids for this DTO
Related
I have entity Document, which has lots of columns, one-to-one, one-to-many and many-to-many mappings to some other entities.
Example:
Document:
id,
title,
body,
authors,
viewers,
...
Using REST, I want to update some particular document, controller receives serialized Document object, calling EntityManager's merge method persists null results to the database if controller received for instance only body , then I want the body to be updated only, but merge deletes records for title, authors and viewers and etc.
I understand that it is a standard behavior of EntityManager, but I am asking what is the most preferred technique to do updates on entities without receiving whole entity from front-end or some other endpoint. Should I load the entity from database using the id I received and set MANUALLY all of the fields and then save to database or should I use another technique.
I don't have any problem with writing manually all of the setters to copy the changes, but entities are really big in size with lots of relations. Asking for best practice in this case.
I know about DTOs but I want alternate approach when using entities for controllers and service methods.
For entity partial update, you will need to use either criteria api or jpql ... if you are using older versions with no criteria update or old query parser where jpql update is not allowed you will have to read from database first, update then insert again .... you can also make use of updatable=false for columns that should be only set on creation (like CREATION_DATE) and there is also a nice feature in hibernate called #DynamicUpdate which I haven't tried but looks brilliant ... It only updates the modified field (check Vlad's post here) ... concerning the DTO DP , I you might always need to use if you want to hide / modify some data from the client regardless to the way you store the data ... and it's always a good way to separate concerns (but comes with the mapping headache between domain & DTO objects which is much released thanks to spring converters)
There are two options one is update query, which works fine but you may feel
you are loosing some hibernate features and simplicity of the code. Else you can do it in Hibernate way like below
AuditorBean auditorBean = (AuditorBean) session.get(AuditorBean.class, AuditorBean.getId());
auditorBean.setFirstName("aa");
auditorBean.setLatName("bb");
auditorBean.setTrainLevel("ISO");
auditorBean.setAccessLevel(4);
Here you should not call any method like saveOrUpdate() or merge().
object is attached with transaction, so object is flushed and committed at the end of the transaction automatically .
I have many issues with LazyLoadingException in a Spring web application wherever I try to access fields that are annotated with FetchType.LAZY
There is no session configured in Spring because the requirement is that the API should be stateless.
All the service layer methods have #Transactional annotations properly set.
However when I try to access the Lazy fields on any domain object, I get the famous LazyInitializationException (...) could not initialize proxy - no Session
I thought that Hibernate would automatically load the lazy fields when needed when I'm in a #Transactional method but it appears it doesn't.
I have spent several days looking for answers but nothing fits my needs. I found that Spring could be configured with openSessionInViewFilter but it appears to cause many issues, moreover I don't have any session.
How to automatically load lazy fields in #Transactionalannotated service methods with such a stateless API ?
I'm sure I'm missing something obvious here, but I'm not very familiar with Spring and Hibernate.
Please tell me if there are missing information in my question I should give you.
LazyInitializationExceptions are a code smell in a same way EAGER fetching is too.
First of all, the fetching policy should be query-based on a business case basis. Tha DAO layer is solely responsible for fetching the right associations, so:
You should use the FETCH directive for all many-to-one associations and at most one one-to-many association. If you try to JOIN FETCH more than one one-to-many associations, you'll get a Cartesian Product and your application performance will be affected.
If you need to fetch multiple collections, then a multi-level fetching is more appropriate.
You should ask yourself why you want to return entities from the DAO layer. Using DTOs is a much better alternative, as it reduces both the amount of data that's fetched from the DB and it doesn't leak the Entity abstraction into the UI layer.
My question is related to strange read/select behavior when same query returns different results after each call. Description of my situation is written below:
I have the following code, returning list of documents from DB
#RequestMapping(value={"/docs"}, method = RequestMethod.GET)
#ResponseBody
public ArrayList<Document> getMetaData(ModelMap modelMap) {
return (ArrayList<Document>)documentDAO.getDocuments();
}
DocumentDAO.getDocuments looks like
public List<Document> getDocuments() {
Query query = entityManager.createQuery("from Document");
List<Document> list = query.getResultList();
for(Document doc:list) System.out.println(doc.getName()+" "+doc.isSigned());
return list;
}
In other controller, I'm also extracting Document and changing boolean property with
Document doc = documentDAO.getDocumentById(id)
doc.setSigned(true);
documentDAO.updateDocument(doc); // IS IT NECESSARY??
getById and updateDocument are the following:
public Document getDocumentById(Long id) {
return entityManager.find(Document.class, id);
}
#Transactional
public void updateDocument(Document document) {
entityManager.merge(document);
entityManager.flush();
}
Questions:
As far as I know, setting property of managed object is enough to propagate changes to DB. But I want to flush changes immediately. Is my approach with extra call of update is appropriate solution or calling setter is enough for making immediate changes in DB? By extra update I mean documentDAO.updateDocument(doc); // IS IT NECESSARY??
How JPA stores managed objects - in some internal data structure or simply keeps them in references like Document doc;? Internal structure most likely makes duplicate/sameID managed object impossible, references most likely makes possible to have multiple managed objects with same id and other properties.
How merge works internally - tries to find managed object with the same ID in internal storage and, in the case of detecting, refreshes it's fields or simply updates DB?
If internal storage really exists (most likely this is persistence context, futher PC), what is criteria for distinquish managed objects? #Id annotated field of hibernate model?
My main problem is different results of entityManager.createQuery("from Document");
System.out.println(doc.getName()+" "+doc.isSigned()); shows isSigned true on odd calls and false on even calls.
I suspect that first select-all-query returns entities with isSigned=false and put them to PC, after that user performs some operation which grabs entity byID, sets isSigned=true and just extracted entity conflicts with already presented in PC. First object has isSigned=false, second has isSigned=true and PC confused and returns different managed objects in rotation. But how its possible? In my mind, PC has mechanisms to not allow such confusing ambigious situations by keeping only one managed object for each unique id.
First of all you want to enrol both the read and the write in a single transactional service method:
#Transactional
public void signDocument(Long id) {
Document doc = documentDAO.getDocumentById(id)
doc.setSigned(true);
}
So this code should reside on the Service side, not in your web Controller.
As far as I know, setting property of managed object is enough to propagate changes to DB. But I want to flush changes immediately. Is
my approach with extra call of update is appropriate solution or
calling setter is enough for making immediate changes in DB? By extra
update I mean documentDAO.updateDocument(doc); // IS IT NECESSARY??
This applies only to managed entities, as long as the Persistence Context is still open. That's why you need a transactional service method instead.
How JPA stores managed objects - in some internal data structure or simply keeps them in references like Document doc;? Internal structure
most likely makes duplicate/sameID managed object impossible,
references most likely makes possible to have multiple managed objects
with same id and other properties.
The JPA 1st level cache simply stores entities as they are, it doesn't use any other data representation. In a Persistence Context you can have one and only one entity representation (Class and Identifier). In the context of a JPA Persistence Context, the managed entity equality is the same with entity identity.
How merge works internally - tries to find managed object with the
same ID in internal storage and, in the case of detecting, refreshes
it's fields or simply updates DB?
The merge operation makes sense for reattaching detached entities. A managed entity state is automatically synchronized with the database during flush-time. The automatic dirty checking mechanism takes care of this.
If internal storage really exists (most likely this is persistence context, further PC), what is criteria for distinguish managed objects? #Id annotated field of hibernate model?
The PersistenceContext is a session-level cache. The managed objects always have an identifier and an associated database row.
I suspect that first select-all-query returns entities with
isSigned=false and put them to PC, after that user performs some
operation which grabs entity byID, sets isSigned=true and just
extracted entity conflicts with already presented in PC.
In the same Persistence Context scope this can't ever happen. If you load an entity through a query, the entity gets caches in the 1st level cache. If you try to load it again with another query or with the EntityManager.find() you will still get the same object reference, that's already cached.
If the first query happens against a Persistence Context and the second query/find will be issued on a second Persistence Context, then each Persistence Context will have to cache its own version of the entities being queried.
First object has isSigned=false, second has isSigned=true and PC
confused and returns different managed objects in rotation. But how
its possible?
This can't happen. The Persistence Context always maintains entity object integrity.
I have a server and clients that are both Java-based and communicate with each other over RMI. The server's data access layer is implemented with JPA and Hibernate and entities are often used as parameters.
The clients do not have Hibernate code and dynamic code download is disabled, so when the server sends an entity to its clients, the actual entity must be sent, not the proxy. Moreover, the entity must be sent as-is, without pre-loading all lazy-fetched attributes because they will never be needed by the clients in most cases.
Is it possible to implement these requirements with Hibernate?
you can fetch all properties in the query
from docs
If you are using property-level lazy fetching (with bytecode instrumentation), it is possible to force Hibernate to fetch the lazy properties in the first query immediately using fetch all properties.
from Document fetch all properties order by name
http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html
or use eagle fetch in your mapping...
The only clean way I know of (that is without fetching every association for the object) is to use a separate object layer for data transportation.
Alternatively you can send the same object types repopulated by you with the necessary data, instead of hibernates objects with the proxies set.
I have an ORM entity loaded by Hibernate, with certain associations LAZY loaded when I need them. This entity is transported thru MQ to client application (and the client is .NET, so I'm using MessagePack to serialize/deserialize) and when the entity is serialized by MsgPack, it tries to access the lazy loaded association and it fails, as the session is already closed. And even if it did not failed, I do not want it to load the association in some cases.
Is there a way to tell hibernate to fill the lazy associations with empty values instead of proxies for some query results or do I have to iterate the returned list and perform these changes by myself?
Thanks for your answers!
You have no other way, but to use DTO objects, to tranfer it through MQ,
Load entity from DB using hibernate
convert it to DTO object which implents Serializable.
Transfer it to consumer using MQ
Convert it to any other entity on other side.
I think that #Transient only applies to ORM. If you do not want your field to be serialized, you should use key word "transient".
private transient List<Object> myTransientList;