Why Lazy loading not working in one to one association? - java

#Entity
public class Person {
#Id
#GeneratedValue
private int personId;
#OneToOne(cascade=CascadeType.ALL, mappedBy="person", fetch=FetchType.LAZY)
private PersonDetail personDetail;
//getters and setters
}
#Entity
public class PersonDetail {
#Id
#GeneratedValue
private int personDetailId;
#OneToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
private Person person;
//getters and setters
}
when i do
Person person1=(Person)session.get(Person.class, 1);
i see two queries being fired. one for fetching person data and another for person detail data.
As per my understanding only 1 query should have been fired that is for fetching person data not for person detail data as i have mentioned
lazy loading. Why personDetail data is getting fetched along with person data ?

Hibernate cannot proxy your own object as it does for Sets / Lists in a #ToMany relation, so Lazy loading does not work.
I think this link could be useful to understand your problem: http://justonjava.blogspot.co.uk/2010/09/lazy-one-to-one-and-one-to-many.html

Based on your comment and since the PersonDetail entity contains a foreign key column that references the Person entity, it looks like you only have 1 problem:
Entity relationships include the concept of a relationship owner (in this case PersonDetail), which means that you want to add a #JoinColumn annotation in the PersonDetail entity.
You have already correctly defined the inverse side of the relationship (the entity that is not the owner of the relationship) with the mappedBy attribute that was added to the association annotation (#OneToOne in your case) to make the relationship bi-directional, which means that the associated PersonDetail may be reached from a Person instance.
Given the relationship that is clarified in your comment, you should only have to make 1 change to your code as shown here:
#Entity
public class Person {
#Id
#GeneratedValue
private int personId;
//Retain the mappedBy attribute here:
#OneToOne(cascade=CascadeType.ALL, mappedBy="person",
fetch=FetchType.LAZY)
private PersonDetail personDetail;
//getters and setters...
}
#Entity
public class PersonDetail {
#Id
#GeneratedValue
private int personDetailId;
#OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
//Change: add the #JoinColumn annotation here:
#JoinColumn(name="PERSON_FK_COLUMN")
private Person person;
//getters and setters...
}

Related

Hibernate: Can we have a relationship between Entities in which both are owning-side?

I am learning Hibernate and came across the terms Owning-side and Non-owing side.
Upon reading, I came to know that Owning-side means the Entity who has FK reference to the other Entity.
Consider the below scenario:
User entity:
#Entity
public class User {
#Id
private int userId;
private String userName;
#OneToOne
#JoinColumn("VEHICLE_ID")
private Vehicle vehicle;
// other code
}
Vehicle Entity:
#Entity
public class Vehicle{
#Id
private int vehicleId;
private String vehicleName;
#OneToOne
#JoinColumn("USER_ID")
private User user;
// other code
}
If I keep the #JoinColumn in both these Entities, then would both these entities User and Vehicle become owning-side entities?
I am not able to understand as to why just placing #JoinColumn annotation makes an entity as the owning-side Entity.
Can anyone help me understand?
If I keep the #JoinColumn in both these Entities, then would both
these entities User and Vehicle become owning-side entities?
We don't start with using the #JoinColumn in an entity and then state that particular entity is an owning entity. In fact the reverse is true.
We first decide which should entity should be owning entity and which one should be non-owning.
And we decide that by looking at which entity has the Foreign Key reference. And this again is more of a design choice. The one having the foreign-key reference is said to be the owning entity.
We then use the #JoinColumn annottation in the owning entity to specify the foreign key.
And in the non-owning side, we use mappedBy attribute inside of the particular association type.
In your example you are specifying a bi-directional relationship. So if we consider Vehicle entity has the foreignKey as userId, then Vehicle entity would be our owning-entity and we annotate this 'userId' with '#JoinColumn'. And in the non-owning entity i.e. User entity, we would use the 'mappedBy' attribute to refer to the field in owning entity on which #JoinColumn has been used :
#Entity
public class User {
#Id
private int userId;
private String userName;
#OneToOne(mappedBy="user")
private Vehicle vehicle;
// other code
}
#Entity
public class Vehicle{
#Id
private int vehicleId;
private String vehicleName;
#OneToOne
#JoinColumn("USER_ID")
private User user;
// other code
}
Here is a detailed documentation that might help you as a reference :
The JPA API reference docs also provide a nice brief description for the different association types : OneToOne , OneTomany , ManyToMany

EclipseLink composite PK with FK

I am using eclipselink 2.5.1.
Let's say I have these two class.
JAVA
#Entity
public class Car implements Serializable {
#EmbeddedId
protected CarPK carPK;
private String color;
#ManyToOne(fetch = FetchType.LAZY)
private Manufacturor manufacturor;
//constructors, getters & setters...
}
#Embeddable
public class CarPK implements Serializable {
#NotNull
private int idManufacturor;
#Temporal(javax.persistence.TemporalType.DATE)
private Date date;
//constructors, getters & setters...
}
Car has a composite primary key (idManufacturor and date) and idManufacturor is also a foreign key referencing the class Manufacturor.
I'm having issue with the mapping. EclipseLink understand the manufacturor object as a column in my Car table.
Error
Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: invalid column nameĀ : 'manufacturor'.
I know the problem will be solved if I add a column manufacturor FK but it would be repeating.
Please feel free to ask for any precision if I'm not clear enough.
Thank you for your help.
Add the JoinColumn Annotation
#JoinColumn(name = "id_manufacturor", referencedColumnName = "id")
Name is the FK column name in your database (not entity).
The referencedColumnName "id" must correspond to the defined id in manufacturer table.

JPA OneToMany with Jointable, deleting a link deletes right-side object

(OpenJPA2.x) I have Parent->(linktable)->Category relation. If I remove category from parent's category array it gets properly deleted from the linktable (unlinked). Adding a new category to an array gets inserted to the linktable. However problem is category target entity is also deleted from Category table. I have debugged jdbc queries and it's performed by OpenJPA library, db tables don't have a cascaded delete constraint.
Parent(key=ServerId,Code)
ServerId|Code |Name
1 |code1|name1
1 |code2|name2
1 |code3|name3
2 |code1|name4
Category(key=ServerId,Code)
1 |cat1 |child1
1 |cat2 |child2
2 |cat2 |child3
LinkTable(key=ServerId,PCode,CCode)
ServerId|PCode|CCode
1 |code1|cat1
1 |code1|cat2
1 |code3|cat1
Parent->Categories are linked using OneToMany annotation. Category does not know where it was linked from so prefer keeping that entity class clean as possible without any link annotations.
#Entity #Table(name="Parent") #Access(AccessType.FIELD)
public class Parent {
#EmbeddedId Parent.PK pk; // contains serverId+code fields
private String name;
#OneToMany(fetch=FetchType.LAZY, orphanRemoval=true, cascade=CascadeType.PERSIST)
#JoinTable(name="LinkTable",
joinColumns={
#JoinColumn(name="ServerId", referencedColumnName="ServerId", nullable=false),
#JoinColumn(name="PCode", referencedColumnName="Code", nullable=false)
},
inverseJoinColumns={
#JoinColumn(name="ServerId", referencedColumnName="ServerId", nullable=false),
#JoinColumn(name="CCode", referencedColumnName="Code", nullable=false)
}
)
private List<Category> cats;
public List<Category> getCategories() { return cats; }
}
#Entity #Table(name="Category") #Access(AccessType.FIELD)
public class Category {
#EmbeddedId Category.PK pk; // serverId,Code fields
private String name;
// this entity don't have OneToMany,ManyToOne,etc.. links back to parent
}
This is a legacy application I must use a composited primary keys, but it should not be a JPA problem I guess, after all this is a valid sql schema pattern.
You annotated the association with orphanRemoval=true. That precisely means that categories which are removed from their parent, and are thus orphan, must be removed.

JPA OneToMany insert not setting the id's correctly

I have two entities, let's say
Person.java:
#Entity
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = AUTO)
private long id;
#OneToMany(mappedBy = "personData", cascade = CascadeType.PERSIST)
private List<SkillsData> skillsData;
// ...
}
SkillsData.java
#Entity
#Table(name = "SkillsData")
public class SkillsData implements Serializable {
#Id
#GeneratedValue(strategy = AUTO)
private long id;
#JoinColumn(name = "PERSONID")
#ManyToOne(cascade = REMOVE)
private Person personData;
// ...
}
When I create a person, add a list of type SkillsData to it's skillsData field and persist it everything works with no exceptions thrown, but when I browse the database directly in the SkillsData table the field PERSONID is not populated and because of that the skills added can't be referenced to the right person.
I'm trying to fix this problem for quite some time and I'll be thankful for any help.
The problem might be in the fact that you're not setting SkillsData.personData before persisting leaving it null.
You must set it cause adding SkillsData to the Person.skillsData list is not enough since you declared this side of relationship as inverse(mappedBy attribute).
Therefore it is the SkillsData.personData non-inverse side who is responsible for establishing this relationship.

JPA : Can we use different collection type on either sides of ManyToMany relationship?

Can we use java.util.List in one entity and java.util.Set in related entity for ManyToMany relationship? For example:
#Entity
public class Employee {
#Id
#Column(name="EMP_ID")
private long id;
...
#ManyToMany
#JoinTable(
name="EMP_PROJ",
joinColumns={#JoinColumn(name="EMP_ID", referencedColumnName="EMP_ID")},
inverseJoinColumns={#JoinColumn(name="PROJ_ID", referencedColumnName="PROJ_ID")})
private Set<Project> projects;
...
}
#Entity
public class Project {
#Id
#Column(name="PROJ_ID")
private long id;
...
#ManyToMany(mappedBy="projects")
private List<Employee> employees;
...
}
Yes, you can. Why don't you simply try it?
A project might want to have employees in a specific order, whereas an employee might just want to have a set of projects.

Categories