I am bit beginner on JPA and need some help on fetching the Many to One relationship in JPA.
I have below entities.
User which stores all user information . User extends Audiatable abstract class which is for holding auidt paramters like last modified date, creation date etc.
I am trying to add another fields as lastUpdatedByUser which should get fetched from lastUpdatedBy for which I amtrying to add Many-One relationship.
But the relation is not working somehow, am I doing something wrong here?
AuditableEntity.java
public abstract class AuditableEntity<T extends Entity<T, ID>, ID> implements Auditable {
private static final long serialVersionUID = 1L;
#Column(name = "cruserid")
private Long createdBy;
#Column(name = "crdate")
#Type(type = JpaConstants.TYPE_LOCAL_DATE_TIME)
private LocalDateTime createdOn;
#Column(name = "chuserid")
private Long lastUpdatedBy;
#Column(name = "chdate")
#Type(type = JpaConstants.TYPE_LOCAL_DATE_TIME)
private LocalDateTime lastUpdatedOn;
#Transient
#ManyToOne(fetch = FetchType.LAZY, targetEntity = User.class)
#JoinColumn(name = "usrId", referencedColumnName = "chuserid")
private User lastUpdatedByUser;
User.java
public class User extends AuditableEntity<User, Long> {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "usrId")
private Long id;
#Column(name = "usrName")
private String name;
#Column(name = "loginame")
private String loginName;
}
Well, you marked the association with #Transient, which means that the field is not persistent and should be ignored by JPA.
And you also seem to have two different fields to store the same information: lastUpdatedBy and lastUpdateByUser. Remove the first one, and map the second one as
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "chuserid")
private User lastUpdatedByUser;
This tells that the association is a ManyToOne to the User entity (no need to specify the targetEntity since it's the type of the field), and that this association is materialized by the join column named "chuserid", in the auditable entity's table, and referencing the ID of the User entity (referencedColumnName is only useful when you use composite IDs, or when you reference an entity by a column which is the the ID)
Related
I have a problem with saving child entities.
Here is my example. My model classes look like this:
#Entity
public class ImportDocument {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;
private boolean imported;
#Transient
private Status status;
#Basic
private char statusValue;
#OneToMany(mappedBy = "importDocument" , cascade = {CascadeType.ALL})
private List<ImportDocumentItem> importDocumentItems;
}
#Entity
public class ImportDocumentItem {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "import_document_id")
#JsonIgnore
private ImportDocument importDocument;
}
I have implemented JpaRepository interfaces for both domain classes.
I try to save with:
importDocumentRepository.save(importDocument);
When I save ImportDocument object, everything is inserted. But the problem is that, the import_document_item.import_document_id (which is foreign key of import_document_id) attribute is filled with null value, not with id of import_document that I expected. How can I fix this issue?
Thanks a lot.
You have to set entity relations on both side before saving. Here an example
ImportDocument importDocument = new ImportDocument();
//...
importDocument.setImportDocumentItems(items);
items.forEach(ImportDocumentItem::setImportDocument);
importDocumentRepository.save(importDocument);
I am using JPA with JSF datatable with lazy loading.
Here One car can be owned by many users. So when i logged in to the application i want the cars which is owned by the user logged in(assume it as userId=1).
I have a mapping table "Cars_User" that contains carId and userId columns.
My Entities are like this
My Car Class
#Entity
#Table(name="car")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
#Transient
private boolean myCar;
#NotNull
#Size(min = 1, max = 50)
public String name;
#OneToMany(cascade = { CascadeType.REFRESH }, fetch = FetchType.LAZY, orphanRemoval = true)
#JoinTable(name = "Cars_User", joinColumns = #JoinColumn(name = "carId"), inverseJoinColumns = #JoinColumn(name = "userId"))
private List<User> carUsers = new ArrayList<User>();
getters ...
setters ...
}
User Class
#Entity(name = "User")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String firstName;
private String lastName;
}
I have found one answer for Lists of String collection in this link but how can be achieved in my case.
I wanted to do get all Cars entities in criteria api that contains the logged in user id "userId" in carUsers Lists. can anyone please help?
I found the solution. I have passed the logged in user Object "user" in isMember function. This may help for somebody.
CriteriaBuilder criteriaBuilder = em.getEntityManagerFactory().getCriteriaBuilder();
CriteriaQuery<Car> criteria = criteriaBuilder.createQuery(Car.class);
Root<Car> root = criteria.from(Car.class);
criteria.where(criteriaBuilder.isMember(user, root.get(Car_.carUsers)));
List<Car> cars = em.createQuery(criteria).getResultList();
What is the difference between these 2 codes. The 1st one shows null on my foreign key which is individualId. The 2nd one is not. Why?
//1st code:
#Entity
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Individual {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "INDIVIDUAL_ID")
private Long individualId;
#OneToMany(mappedBy="individual",cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Identification> identifications = new ArrayList<Identification>();
}
#Entity
public class Identification {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "IDT_ID")
private Long id;
#ManyToOne
#JoinColumn(name="individualId")
private Individual individual;
//second code
//replaced #OneToMany in the first code & then i just dont add #ManyToOne in the Identification Class and it works fine. Why?
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "INDIVIDUAL_ID", referencedColumnName = "INDIVIDUAL_ID")
private List<Identification> identifications = new ArrayList<Identification>();
When i search for JPA tutorial in google the 1st code is the one that i always read. declare #OneToMany in the parent class and add mappedBy, declare #ManyToOne in the child class. But why the 2nd code works perfect than the 1st code? it just let me declare #OneToMany only in the parent class ?
In the class Identification the name of the #JoinColumn does not match any column in your class Individual. It must be the name of the column in the database, which is INDIVIDUAL_ID:
#JoinColumn(name="INDIVIDUAL_ID")
I'm facing an issue i can't figure out.
I got 2 entities : User and Course with a Many to Many relationship
User.java
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
#ManyToMany(cascade = CascadeType.MERGE)
#JoinTable(
name="USR_COURSES",
joinColumns=#JoinColumn(name="USR_ID", referencedColumnName="ID"),
inverseJoinColumns=#JoinColumn(name="COURSE_ID",referencedColumnName="ID"))
private List<Course> courses;
...
Course.java
#Entity
#Table(uniqueConstraints=#UniqueConstraint(columnNames="CODE"))
public class Course implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String code;
private String name;
private String content;
#ManyToMany(mappedBy="courses",cascade = CascadeType.MERGE)
private List<User> users;
...
If i create a user and set him some courses, the join table will be updated with the new relations between the User and the Courses.
However if i want to edit a user by adding him courses, the join table is not update :
List<Course> test = myUser.getCourse();
test.add(facade.find(1l));
myUser.setCourse(test);
userFacade.edit(myUser);
I'm using NetBean and the AbstractFacade generated.
Thanks for helping !
In order for the cascade to work in that case you would need to set dependencies in the both sides of the ManyToMany relationship.
That means that you would need to do the following:
List<Course> test = myUser.getCourse();
Course course = facade.find(1l);
course.getUsers().add(myUser);
test.add(course);
myUser.setCourse(test);
userFacade.edit(myUser);
When you query for the Course you do not get the user list because you only have Cascade.MERGE set up on that relationship. This means that you need to set it manually as above.
The mappings between the 2 tables(Department and Employee) is as follows (Link for the image showing mapping is also provided):
Every department has one and only one department head.
Every department can have more than one employee.
dept_id and empId are primary keys of their respective tables.
dept_head(It is the Employee Id) and dept are foreign keys of their
respective tables.
Mapping Employee and Department table
I created entity classes for the above 2 tables (The structure is provided below).
Employee Class:
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "empId")
private Integer empId;
#Size(max = 45)
#Column(name = "name")
private String name;
#Size(max = 45)
#Column(name = "address")
private String address;
#Size(max = 45)
#Column(name = "grade")
private String grade;
#Size(max = 45)
#Column(name = "email")
private String email;
#JoinColumn(name = "dept", referencedColumnName = "dept_id")
#ManyToOne
private Department deptartment;
.. ...
}
Department class:
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 8)
#Column(name = "dept_id")
private String deptId;
#Size(max = 45)
#Column(name = "name")
private String name;
#JoinColumn(name = "dept_head", referencedColumnName = "empId")
#OneToOne
private Employee deptHead;
#OneToMany(mappedBy = "deptartment")
private List<Employee> employeeList;
....
...
}
If I am adding mappedBy in Employee Class (like I did in Department), to show OneToOne mapping between empId and deptHead,the code is compiling and running. However, If I do not add the mappedBy statement in Employee class, as the above code shows, the code still compiles and runs fine.
I would want to know why the code above works even if I am not providing mappedBy in employee class.
If anybody can help me clearing the above doubts and explaining the logic behind its working would be great as I am new to this.
It is not quite clear where you tried to user it with and without the mappedBy attribute.
But if I get your question correctly, you ask why you can have only one or both sides annotated?
It depends on which side is the source and destination of your relation or wheter it's bi-directional. On the Java-side you can have a relation always in both directions due to object references, but on the Database-side, you might only have it in one direction.
Check out JPA Wiki book on that topic for more details.
Additionally, the API doc for OneToOne states:
Specifies a single-valued association to another entity that has
one-to-one multiplicity. It is not normally necessary to specify the
associated target entity explicitly since it can usually be inferred
from the type of the object being referenced. If the relationship is
bidirectional, the non-owning side must use the mappedBy element of
the OneToOne annotation to specify the relationship field or property
of the owning side.