Is it OK to have only bidirectional relationships with Hibernate? - java

So the question is pretty much in the title.
Let's say I have some classe: User, Post, Comment and Tag.
User has a #OneToMany List and
#OneToMany List.
Post has
#ManyToOne User, #OneToMany
List, #ManyToMany List.
Comment has #ManyToOne List,
#ManyToOne User.
Tag has #ManyToMany
List.
I'm new to Hibernate, but I find it easy then to use for example the attributes of a Tag object to get all the Post objects related to that tag, or find the author of a Post object or all the Post written by a certain User.
Is it OK ?
I'm talking more in terms of performance here. I'm also using the Play! framework. I don't know if this changes anything.

I think some of them should be unidirectional.
For example, in real-world scenario you usually don't need to display "all Posts by User", because they should be filtered or paginatied, so you need to run queries against the database instead of retrieving Posts from the User (because not filtering a collection at the database side in these use cases can be a real performance problem, especially if that collection is huge).
Therefore having collection of Posts in User makes no sense. The same is true for User - Comment and Tag - Post relationships.

It is ok to have bidirectional relationships. The real danger is in also having lazy false, because then you will end up loading a lot of your db into memory for every request.
If you have bidirectional relationships, it is good practice to create specific dao methods that allow you to load only the data you need, with hql.

Related

Prevent lazy loading in JPA/Hibernate with FetchType.LAZY (especially when using #Transactional)?

I searched around but I only get people asking the opposite of my question. So let's say we have:
#Entity
class Book {
...
#ManyToOne(fetch = FetchType.LAZY)
private Author author;
}
Is there a (preferably global) property/way in JPA/Hibernate to prevent from ever lazily loading the author (or any entity)?
Don't get me wrong, I don't want to use EAGER fetch. I want to prevent juniors from ever accidentally calling book.getAuthor().getName() and making another DB call. A lot of people are looking to fix their LazyInitializationException, but I basically want to force such an exception to be thrown even if there is an active session (which when using #Transactional is quite an easy mistake to make). However I also still want Author to be fetched if you properly use "JOIN FETCH Author" in your JPQL query.
My particular use case is with Spring and GraphQL.
#Transactional quite easily hides when a session is open and avoids the LazyInitializationException.
And with GraphQL you can specify which fields to get so I don't want unnecessarily joins when such fields aren't requested (here we use a Field Resolver with a DataLoader).
Would a sufficient workaround be to instead use a projection (https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections) of the Book entity without the reference to the author? And by working with different projections guarantee that related entities are not unintentionally loaded?

How to speed up List access in JPA

In my mapper class, I always have to retrieve a list of departments from my company entity :
#OneToMany(mappedBy = "company", orphanRemoval = true, cascade = CascadeType.ALL)
public List<CompanyDepartments> getDepartments()
{
return departments; //java.util.List variable.
}
There are a couple thousand departments(about 2000+). I am trying to reduce the time taken to fetch company data and want to begin with the departments which are going to be fairly static in nature.
Option 1 : I can always have a private method in the mapper which populates a cache on the first load and return from the cache all the time.
But is there anything more simpler? I am probably not the first one to face this and wanted to know how I could approach this. Is there a known annotation that can be used. Like a #Singleton annotation on the variable in the entity ? (there is no such annotation obviously). What is the simplest way to make this list a singleton.
Just a typical spring mvc 3 application using spring data jpa for db interaction.
I suggest this link that solves the n +1 query problem ...
How can i resolve the N+1 Selects problem?
Moreover you could put a cache (lvl 2) on your search service,
if the data does not change during the life cycle of the application.
http://docs.spring.io/spring/docs/3.1.0.M1/spring-framework-reference/html/cache.html
Another approach is to add to indexes on the db.
I hope I've given you all the answers about your question.
What you're experiencing is part of the "object-relational impedance mismatch". One solution would be to extend your object model so that you can use a left join fetch to load multiple companies including their departments using only one SQL statement.
The problem using this technique is that you can populate only one list at a time. Although it's nice & easy to define many sub-lists in the world of objects, it's hard to load all these lists at the same time (and therefor efficiently) from a relational database. However it can be done on Oracle using object- or XMLType queries.
The straight-forward way to get such data out of a RDBMS is by writing custom queries that match exactly the task at hand and provide only the data that is actually needed. Therefor you'd need not only one company class, but many - one for each task. - you'd actually do inheritance instead of attribution
BTW, that is why ORM is still considered the Vietnam of Computer science - easy to get started, but hard to succeed with.

Maintaining relationships in JPA 2.0

I've been using JPA 2.0 for a while but, sad to admit, I haven't had enough time to learn it properly. It seems like I lack the basics of how to work with Entity Manager.
Moving one step at a time, I'd like to first ask you about maintaining relationships between mapped entities. Of course I know how to create mappings between entities, different types of available associations (OneToOne, etc.) and how databases work in general. I'm purely focused on maintaining it via Entity Manager, so please do not send me to any kind of general knowledge tutorial :-).
The questions are:
Am I right that as a programmer I'm responsible for maintaining (creating/updating/removing) relationships between instances of entities?
Do I have to always update (set to null, remove from collection, etc.) instances by hand?
Plain SQL can set entities to NULL on deleting, but it seems like JPA can't do such a simple thing. It also seems like a burden to do it manually. Is there a way to achieve that with JPA?
If I have OneToMany relationship and set to NULL the entity on the Many side of the relationship. Then I persist the changes in a Set by saving the entity on the One side. Do I then have to update the entities in the Many side and set association to NULL in each instance? Seems pure silliness for one-directional bindings!
Thanks in advance!
The main thing you need to investigate is the different options you have when mapping on entity. For example in the next piece of code the cascade all option will instruct jpa to delete the child list when the parent is deleted.
#OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.ALL }, mappedBy = "parent")
private Set<Child> events = new HashSet<Child>();
Yes. You maintain the object tree and modify it to look like what
you want.
Yes and no. If you want the entity to reference null, then yes.
For instance, if you are removing one Entity, then you should clean
up any references to it held by other entities that you are not
removing. A practical example: its good practice to let an Employee
know his/her Manager has been let go. If the Employee is going to
stay, it should either have its manager reference nulled out or set
to a different manager, before the current manager can be removed.
If the employee is going to be removed as well, then cascade remove
can cascade to all the Manager's subordinates, in which case you do
not need to clean up their references to the manager - as they are
going away too.
I don't quite understand what SQL is setting to null. Deleting
removes the row in the database, so there isn't anything to set to
null. Cleaning up a reference shouldn't be that difficult in the
object model, as JPA has a number of events to help such as
preremove preupdate etc. In the end though, the problem is with
your java objects. They are just java objects, so if you want
something done, your application will need to do it for the most
part. JPA handles building them and pushing them to the database,
not changing the state for you.
Yes and no. If you set up a bidirectional relationship, you must
maintain both sides as mentioned above. If you set the child's
parent reference to null, you should let the parent know it no
longer has a child, wouldn't you? Your parent will continue to
reference its child for as long as that Parent instance exists. So
even though the database is updated/controlled through the side that
owns a relationship, the object model will be out of synch with the
database until it is refreshed or somehow reloaded. JPA allows for
multiple levels of caching, so it all depends on your provider setup
how long that Parent instance will exist referencing a Child that no
longer exists in the database.

EJBs and JPA design question

I'm using EJB 3.1 and JPA 2.0.
I'll give you an example to explain my doubts and ask for hints as what is a good practice and what's not.
Let's say I have an EJB that's a user Facade. So you have something like this:
#Stateless
public class UserRepository {
public User find(Long id) {
...do user lookup using entitymanager.
}
}
Alright, now let's say I return the User entity from this and that this entity has a collection of comments (Comment being also an entity).
I could have a Comment Repository with a findCommentsByUser(Long userId) method, or I could fetch the user and call the getComments() method. May be this case is simple, but I've faced this decision many times sometimes not knowing what is best.
Also, let's say I want to add a comment, should I add it to the comment collection the entity has and the have the entity merged, or should I have a addComment(Long userId, Comment newComment) method?
I'm looking for advice or best practices regarding this. If you need further clarifications please do not hesitate to ask.
EDIT:
I've found the comments so far helpful, however notice this, it isn't really about users and comments, I just made that up to explain my situation. It's about whether it is convenient to mix both approaches (which I think is not) or is one better over the other. I liked the "always persist through the repositories" suggestion. But the fact that I have a fetchComments() repository method and the getComments() in the user entity creates to entry points for the same functionality, so how do I deal with that?.
Also the performance (1 query vs 2 queries) isn't really important because I will be fetching the user entity too so it's not like I'm actually saving anything.
We typically only work with detached entities in our applications, so we have a data access manager to fetch and update entities. Then we know that anything we do in our business logic will not be persisted unless specifically called to. I would also fetch the comments with the user entity, but make sure it is not persisted until explicitly called.
I could have a Comment Repository with a findCommentsByUser(Long
userId) method, or I could fetch the user and call the getComments()
I would say that from a performance point of view, the first alternative is slightly better, because you don't fech the user (1 query) and then the comments (another query). The first does it in a single shot.
In the other side, i find the second more readable, abstract, and object oriented approach. I would use this one.
You would generally add the getComments() method to your user object. When you want to add one, you would add it to the user set and then call update on the user object.
I think this highly depends on the requirements, on how fine-grained control of the process do you want to have (this often depends on the performance requirements and expected load, etc.).
If the comments are never to be retrieved independently, I would only keep them as a reference inside User.
If you, however, want to get the comments regardless of the user, or you want to perform some other comments-related queries (like all the comments for users in group A), then I would create separate CommentsRepository.
If you want to be able to add the comment to a user that's not loaded from the DB, but you have the foreign key, you may simply want to add the comment through CommentsRepository like you suggested (also adding a comment to a list of user's comments in parallel and persisting such two lists into DBs may result in 'weird behavior').
There are several considerations that needs to make I hope I will document them here for you.
Domain model is important consideration in EJB3. In your example if you see your domain model allows you to fetch comments lazily because in any flow you show user details first and then his comments.
In some cases your collection (I am referring to comments here) may contain lots of data, In this case its hardly question of string data so not a major concern, but if it would have been real application data then always opt for transient relationship and provide appropriate methods to fetch them independently.
Its never a good practice to expose your collection inside entity bean to outside world so if you OneToMany or ManyToMany relationship then you should provide three basic methods over collections (add, remove, get).
Collections.unmodifiableCollection method should be used while returning collections from get method.
Always use Set when you are using collections inside entities remember they do not allow duplicate.
In your case comments collection has direct dependency on user so you should use cascade type in user to save comments.
I am not convinced why you need UserRepository because em.find method will do job for you.
By default for OneToMany relation fetchtype is lazy so if you want to do eager load you will need to specify it.
I hope these guidelines hopes to solve your problem.
Regards,
Amit

Hibernate usage in a Servlet environment

I'm trying to create a domain object that contains objects in a read-only fashion but be able to modify which objects it points to.
So in the example below I would like Hibernate to handle populating the Account and Category objects but I don't want to ever update those objects. However I may wish to change which Account or which Category I want Expense to point at.
In other words I may wish to update the account_id or category_id on the expense table but I never want to update the account or category table with changes I've made on the Account or Category objects contained in the Expense object.
#Entity
#Table(name = "expense")
public class Expense {
#Id
#GeneratedValue
private long id;
private String name;
private BigDecimal amount;
#OneToOne
#JoinColumn(name = "id", referencedColumnName = "category_id")
//From table called category
private Category category;
#OneToOne
#JoinColumn(name = "id", referencedColumnName = "account_id")
//From table called account
private Account account;
Am I totally misusing Hibernate or is it just not the right tool? Should I define my own sql with #SQLUpdate and #SQLInsert?
The general flow of the application is standard web app stuff.
Load data from database
Display on form
Gather changes made by user
Persist those changes
Thanks
It is a bit of a departure from the intent of hibernate. Changes to persistent objects, are supposed to be persistent. Don't change them if you don't want their state to be saved! Explaining and thus better understanding for yourself why you want that kind of behavior might help you arrive at a solution (or help us help you.)
One option you have is to detach/evict the mapped objects that you don't want to be changed inside your data access layer before returning the Expense object. Then as long as no cascading is on, changes made to them won't be saved. IMO this leads to "surprising" behavior for other programmers.
Another option is to use hibernate in a Sessionless manner. Each call is its own atomic database operation and all objects are detached after returning. Then only entities that you explicitly call saveOrUpdate on will get saved to the database. You can learn how to configure Hibernate to work this way in the Hibernate reference docs, although again, I don't know why you'd want to if you're not trying to emulate the behavior of some legacy system you're uplifting.
One final point to understand, withing a Session, the Category that you get by calling expense.getCategory() will usually be the same actual object that you get by calling session.get(Category.class, 123). So if both ways of accessing it are available inside the same Session, it will be easy to lose track of its entity state if you're trying to manually manage it.
edit:
Ah-ha! Now it makes more sense.
If you're doing purely CRUDy web form screens, you don't have much to worry about. As long as you don't have any Cascading on, when you merge back the detached Expense object, changes on the Category and Account aren't going to end up in the database. You could null out every other field, and as long as the id is still there, you're ok. (Assuming you don't have other things like cascading validation that would cry about it.)
There are two basic patterns for handling this a little bit better.
One is to put the Expense object on the user's web session. This way you have the entire thing, and your web data binding framework only needs to bind back onto it the fields that are actually changed by the form. The original Category and Account are still there (or proxies of them) and the binder doesn't need to munge them. Downside is of course adding server side state, as well as needing to clean it up.
Two is to register data binders that actually go into the database and get the mapped entity during web binding. So all that would actually appear in the form is the ID of the mapped field, and the binder will go fetch and put the full object there for you. Downside is possibly unneeded round trips to the database, but aggressive L2 caching can fix that (assuming Categories almost never change and Accounts rarely change.)
You may also want to look into the OpenSessionInView/OpenEntityManagerInView patterns if you're presently using hibernate in an essentially sessionless manner by creating and disposing sessions within the DAO.

Categories