Relational Data is Not Fetching in Ebean - java

Background
I am using Play Framework(Java) to store data. Play Framework uses Ebean to convert classes into data that can be stored in a a database.
Issue
I am currently having trouble fetching relational data completely. I have a User and a UserEmail model. The User can own multiple UserEmails.
User Model Code
User Email Model Code
When I try and fetch a User, the User data is fetched correctly, however the UserEmails are not.
Fetching Code
When I specifically add fetch("emails") to the fetch code
User.find.fetch("emails").where().eq("userId", testUserId).findUnique();
It seams like it at least gets the emails. However when I try and show them via
return ok(Json.toJson(retrievedTestUser));
I get This Error
Question
Is there some way I can make Play Framework/Ebean automatically fetch the emails without adding fetch("emails") to every query? Maybe an annotation?
How do I resolve the error above? I get why it is thrown, but how can I fix it? Is there any way to have it only fetch one level deep?

I have found solution to above problem. Every entity should have id.
User class has field annotated with #Id but UserEmail has not.
After adding #Id annotation above email field of UserEmail class user is fetched properly and its email list is not empty.
#Id
public String email;
One more thing that I spotted in your code:
When you are creating bidirectional relation then you should use mappedBy attribute on one side to indicate that these are two ends of one relation and not two separate relations. So there should be:
#OneToMany(mappedBy="user", cascade = CascadeType.ALL)
#Constraints.Required
public List<UserEmail> emails;

Related

Hibernate relationship mappings - must?

In hibernate we can map entity relationships with one to one, one to many, etc. I am little bit skeptical about using the relationship annotations and I prefer to use individual find methods to retrieve child records. Example,
Lets consider I have two tables, User and Roles. Each user can have one role. So the entities are,
class User {
#Column
private String name;
#OneToOne(mappedBy="role_id")
private Role role;
.... getter/setter....
}
class Role {
...
}
Either we have to make eager fetch or it will lead to lazy initialisation exception if the role is accessed outside of the current session.
Instead of this, shall we have the mapping like this?
class User {
#Column
private String name;
#Column
private Long roleId;
....
}
This way, whenever we need the role details, we can get the role_id from the User object and query the role table? Is this a right approach? Yes, I know the benefit of loading object graph, but I think this approach will avoid the unnecessary eager fetches and will run seamlessly if we do database partitions.
(I always consider databases as just datastore and use use individual queries to retrieve data instead of using joins to avoid load on the DB).
Please let me know your thoughts.
I suggest using
class User {
#Column
private String name;
#OneToOne(mappedBy="role_id")
private Role role;
.... getter/setter....
}
class Role {
...
}
Don't see point in calling database select twice. Database can handel joins good and do select very fast so I don't see point to manually do it. Also when using this approach you can easy save/update/delete objects.
To avoid lazy initialisation exception you can use Hibernate.initialize(Object obj) as explained here How Hibernate.initialize() works.

Spring mulitple rows with hibernate bean

We are migrating to spring & hibernate from struts1.x and JDBC.
Facing issue while adding multiple rows in jsp (like mapped properties in struts1.x) based on user preferences (Ex: Adding/deleting employees to Manager) in spring.
In service layer, getting Manager Object (as persistent object returned by hibernate )then displaying manager object in JSP. Employee row will be deleted by using java script/jquery from html form by user delete action, upon form submission spring does not delete in the respective employee from the list of employees of Manager object (model attribute). I have worked on some examples without hibernate where the object is being deleted from the list and works well but not in the hibernate prepared object.
ex: lets say Manager object have 3 employees as List when displaying on screen, when user will delete one employee row and submitted then spring needs to populate the Manager object with two employee objects as list since one employee is deleted by user in UI.
I suspect that, this behavior with PersistentBag implementation of Hibernate?
Anybody experienced this problem earlier? Any ideas would be greatly appreciate.
It might depends on how the pojo is declared..
Sure you are deleting a manager, but how is the manager connected to the employee?
If on the manager you have a Employee Object, you should have
#OneToOne(cascade=CascadeType.ALL, orphanRemoval=true, fetch=FetchType.EAGER)
#Fetch(FetchMode.SUBSELECT)
#JoinColumn(name="EMPLOYEE_ID", nullable = false)
private Employee employee;
This way, if you delete the manager object, it will cascade delete the Employee object...
Either your "cascade" is enforced via db, or it must be enforced via annotation.. if you're not doing either, of course nothing will happen...

Relational Data is Not Storing in Ebean

Background
I am using the Play Framework(Java) to store data. Play Framework uses
Ebean to convert classes into data that can be stored in a database.
I am having issues creating One To Many database relationships. I am trying to create a relationship between a User model and a UserEmail model. Where each User may have many UserEmails.
User Model Code
User Email Model Code
The Issue
When I create a User and then add a UserEmail, it does not seam to save the UserEmail in the database. I have tried doing so many ways.
By adding to the List<UserEmail> emails and then saving the User(Code)
Result: New User is stored in database with correct info, However no new UserEmail is stored in the database
By creating a static create method in UserEmail(Code)
Result: No UserEmail was stored in the database
By adding to the List<UserEmail> emails and then saving the UserEmail and the User(Code)
Result: New User is stored in database with correct info, However no new UserEmail is stored in the database
Question
In Play Framework(Java), how do you create and store Relational Data? Is there some step I am missing? Do I have to add another Annotation to the models to make it work?
Update
After some further testing it looks like saving the User object with a new UserEmail will save it to the database. However when I fetch a user
User retrievedTestUser = User.find.where().eq("userId", testUserId).findUnique();
It does not retrieve the UserEmails
Add information about reverse field:
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
public List<UserEmail> emails;
Details in documentation
Above problem was because there was #Id annotation missing in UserEmail class.
Adding below code solves the problem:
#Id
public String email;

Hibernate List is empty when using lazy loading but it has results when eagerly loaded

I two entities a User and a Place witch are bound with many to many association.
When I try to get all the places for a given user thought the getter method, an emtpy list is returned but the user is bound to the place in the database and if I change the default fetching strategy to eager I can see all the places just fine.
I am using MySQL for the persistance.
The annotations used are:
for the User entity:
#ManyToMany
#JoinTable(name= "USER_PLACE",
joinColumns = {#JoinColumn(name="USER_ID")},
inverseJoinColumns = {#JoinColumn(name="PLACE_ID")})
private List<Place> places = new ArrayList<Place>();
and for the Place entity:
#ManyToMany(mappedBy = "places")
private List<User> users = new ArrayList<User>(0);
What can it be the cause of this?
To me, it looks like a Mapping issue in Your domain-model. Do the provided entities also map somewhere else? You might run into crazy joins with other tables. Could you provide all relevant entities? Also, the SQL statements generated by Hibernate for User.getPlaces() would be helpful.

Hibernate returns only one result (After changing table names)

I am using hibernate retrieve results from my MySQL database into my Java project. Recently, I had a lot of redundant data and had to manually clean up the database by copying the required data into new tables and then renaming the newly created table to old table.
But, now querying the database with hibernate gives only one row as the result. I have manually checked the database and there are several different rows in the database. My query to Hibernate is something like this:
Criteria c = session.createCriteria(UserDto.class);
c.setMaxResults(100);
List<UserDto> users = c.list();
users contains 100 elements but all are the same.
The mapping of userDto is here.
Any idea what is happening here?
If your UserDto class has ToMany relations, then this is quite possible that outer join on them results in many records which all contain one and the same user data. You should use
session.createCriteria(UserDto.class).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
Double-check your mapping of the UserDto class to the database.
My guess is that you don't have it mapped to the table that you think you do.
As Sebastien mentioned, setting hibernate.show.sql to true should make this obvious.
Did you deleted the old tables? And in the configuration file what is the value for "hibernate.hbm2ddl.auto"?
I think the reason is these records have same id, so Hibernate treat them as the same record. You can check it.
I had same problem. In my case, the problem detected when I created a table in MySQL manually and I tried to read data from that table using hibernate and a dto class. After checking my dto class fields and database table, I figured out that there is a difference between table column named "id" and the class field which named dbId. The code was something like this:
#Id
#GeneratedValue
#Column(name="db_id", unique = true)
private long dbId;
So I edited the name and changed the code:
#Id
#GeneratedValue
#Column(name="id", unique = true)
private long dbId;
Which "id" was the correct name of databse table column and the problem has been solved.

Categories

Resources