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;
Related
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
We are using JPA + Hibernate.
I have some Many-to-one mappings which are lazy loaded.
In Service, I Initiallize the Many-to-one objects by calling their getter method. but proxy gets assigned to parent VO and not actual VO Object.
My Question is, Is there any way in JPA to force to use no proxy Strategy.
My limitation here is i cant use Hibernate Objects or annotaions like #LazytoOne etc.
thanks in advance.
You cannot prevent Hibernate from using proxy objects there due to the fact that somehow it has to guarantee it's a lazy relation.
You have multiple choices:
Trigger the initialization Hibernate.initialize(parent.getChild()). Note that this is not the best way to do it and this also requires an active transaction.
Fetch the relation when fetching the entity itself. This can be done with the Fetch Joins. JPQL/HQL/Criteria API are capable of doing this.
Use read-only projections which contains only the data you need. For this particular case you can use Spring Data JPA as it comes with such a feature.
I suggest you to go with either option 2 or 3 as they are the most effective ways to do this.
Furher reading about lazy-loading here.
Within an Entity class, can I have any object as an attribute and when I persist the Entity to the database will it also persist that objects attributes?
If the object is serializable, you could serialize it as a BLOB. But that's not something you want to do because
it would be inefficient to constantly serialize and deserialize the object
it would be very fragile: a change in the object class would make it impossible (or hard if you know what you're doing) to read previous versions already saved in the database
only Java could make sense of the blob
you could not do any query on this object
So, basically, the answer is no. JPA entities can have embedded objects, whose fields are mapped to columns, or can have associations with other entities (OneToOne, OneToMany, ManyToOne or ManyToMany).
My advice: think about the design of your database first, then map the schema to JPA entities. If you start writing an object model without even thinking how it will be persisted in the database, you won't go very far.
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'm having a problem where JPA is trying to lazily load my data when I don't want it to. Essentially what is happening is I'm using a Service to retrieve some data, and when I go to parse that data into JSON, the JSON library is triggering hibernate to try and lazily load the data. Is there any way to stop this? I've given an example below.
// Web Controller method
public String getEmployeesByQuery(String query) {
Gson gson = new Gson();
List<Employee> employees = employeeService.findEmployeesByQuery(query);
// Here is where the problem is occurring - the gson.toJSON() method is (I imagine)
// using my getters to format the JSON output, which is triggering hibernate to
// try and lazily load my data...
return gson.toJSON(employees);
}
Is it possible to set JPA/hibernate to not try and lazily load the data?
UPDATE: I realize that you can use FetchType.EAGER - but what if I don't want to eager load that data? I just want to stop hibernate from trying to retrieve more data - I already have the data I want. Right now whenever I try and access a get() method hibernate will throw a "no session or session is closed" error, which makes sense because my transaction was already committed from my service.
Thanks!
There are several options:
If you always need to load your collection eagerly, you can specify fetch = FetchType.EAGER in your mapping, as suggested in other answers.
Otherwise you can enable eager fetching for particular query:
By using JOIN FETCH clause in HQL/JPQL query:
SELECT e FROM Employee e JOIN FETCH e.children WHERE ...
By using fetch profiles (in JPA you can access Hibernate Session via em.unwrap(Session.class))
You really have two options:
You can copy the data from employee to one that is not being proxied by hibernate.
See if there is a way to not have the toJSON library reflect the entire object graph. I know some JSON libraries allow you to only serialize some properties of an object to JSON.
Personally I would think #1 would be easier if your library only uses reflection.
As others have stated, this is not an issue with JPA/hibernate but rather with the json serialization library you are using. You should instruct gson to exclude the properties you don't want traversed.
Yes:
#*ToMany(fetch=FetchType.EAGER)
I suggest you to make a fetched copy of the entities you want to use outside of a transaction. That way, the lazy loading will occur from within a transaction and you can pass to Gson a plain, not enhanced, POJO.
You can use Doozer to do this. It is very flexible and through a little configuration (read you'll gonna loose your hair configuring it) you can even retrieve only partially the data you want to send to Gson.
You could always change the fetch attribute to FetchType.EAGER, but it is also worth considering if you have your transactions have the right scope. Collections will be correctly loaded if they are accessed within a transaction.
Your problem is that you are serializing the data. We ran into the same sort of problem with Flex and JPA/Hibernate. The trick is, depending on how much you want to mangle things, either
Change your data model to not chase after the data you don't want.
Copy the data you do want into some sort of DTO that has no relationships to worry about.
Assuming you're using Hibernate, add the Session-in-view filter....its something like that, it will keep the session open while you serialize the entire database. ;)
Option one is what we did for the first big project we did, but it ruined the data access library we had for any sort of general purpose use. Since that time we've tended more toward option two.
YMMV
The easy and straight forward thing to do is create new Data classes (something like DTO)
use Hibernate.isInitialized() to check if the object is initialized by hibernate or not.
I am checking gson if i can override anything. I will post it here if I find anything new.