I have simple entity like :
#Entity
public class University implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
String name;
#Column
String address;
#Column
Student student;
}
And entity Student :
#Entity
public class Student implements Serializable {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
String Firstname;
#Column
String LastName;
#Column
StudentStatus status;
}
Can i create #JoinFormula or something like that to create query , which will take students from Student entity to University entity ?
I tried something like that:
#JoinFormula("SELECT l FROM Student l where l.id = 1")
Student student;
but it doesn't work.
Can i create query to select some students ?
UPDATED :
#JoinFormula never called.
I probably miss the poit, but if you just want to reference another entity you can use the #ManyToOne Annotation.
Example:
#ManyToOne
public MediaLibrary getParentLibrary() {
return parentLibrary;
}
Similary, if you have a list you can use the #ManyToMany Annotation and then specify the correct join Table:
Example:
#ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.REFRESH, })
#JoinTable(name = "MediaDataTag", joinColumns = { #JoinColumn(name = "MediaData_Id") }, inverseJoinColumns = { #JoinColumn(name = "Tag_Id") })
public Set<Tag> getTags() {
return this.tags;
}
If you provide a clear use case, it would be easier to provide a specific solution.
EclipseLink has a great set of JPA documentation and examples (even if you're using a different implementation)
Try using this instead (I assume a university can have more than one student)
#OneToMany(mappedBy="university")
private Set<Student> student;
And in Student you'll have the reverse mapping
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="UniversityID")
private University university;
Related
I want to get data from multiple table.
public class Student{
private int id;
private String name;
private List<Course> course;
}
public class Course{
private int id;
private String name;
private int studentId;
}
I want to fetch data from student and course table using spring data jpa and map to student object.
How can I do that in efficient way?
#Data
#NoArgsConstructor
public class Student{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
#OneToMany(mappedBy="studentId",cascade=CascadeType.ALL,fetch=FetchType.Eager)
private Set<Course> course;
}
You May Use Set Instead of List.
Always Use Mapped By in OneToMany Side, If you use it manyToOne side it will create an
extra table.
You can use Fetch Type eager or lazy. By default, it is lazy with You have
to use #transactional of Lazy.
#Data
#NoArgsConstructor
public class Course{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
#ManyToOne
#JoinColumn(name="studentId")
private int studentId;
}
Hope this Answer Solve your query Happy Coding!.
Note that the starting point might be wrong. I assume that a student can choose multiple courses and a course can be chosen by multiple students. So it is actually a #ManyToMany relationship but not #ManyToOne or #OneToMany.
You will definitely need a joint table to map their primary keys from two tables into the joint table.
#Entity
#Data
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#EqualsAndHashCode.Exclude
#ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
#JoinTable(
name = "courses",
joinColumns = #JoinColumn(name = "student_id"),
inverseJoinColumns = #JoinColumn(name = "course_id"))
private Set<Course> courses;
}
#Entity
#Data
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#JsonIgnore
#EqualsAndHashCode.Exclude
#ToString.Exclude
#ManyToMany(mappedBy = "courses",fetch = FetchType.EAGER,cascade = CascadeType.ALL)
private Set<Student> students;
}
Note all the modifications I have here.
For the data persisted into database, Long is a better choice than int. Similarly, e.g., use Boolean instead of boolean.
Think the Student as the side managing the many-to-many relationship, and Course as the target side. On the target side, use #JsonIgnore and #ToString.Exclude annotations to avoid an infinite recursion, StackOverflow or OOM.
#JsonIgnore
#EqualsAndHashCode.Exclude
#ToString.Exclude
#ManyToMany(mappedBy = "courses",fetch = FetchType.EAGER,cascade = CascadeType.ALL)
Use Set instead of List if a student is not supposed to select the exact same course. It ensures that one can still select 2017 fall Maths and 2018 fall Maths, while one cannot select 2017 fall Maths twice.
I work with an embedded H2 database in which I use the #OneToMany relationship to relate an entity instance (product) to multiple instances of the other entities (suppliers); it's useful when I have specific suppliers for a particular product.
However now, I want to associate all the suppliers with every single product; I don't want to generate in my supplier table different supplier records for each product, instead I want to have only 5 records (5 suppliers) in my supplier table which are associated to every single product, it few words I want to achieve something like "one to all", is it possible to do it using JPA annotations?
Product entity
#Entity
public class Product {
#Id
private String productCode;
#OneToMany
#JoinColumn(name = "supplier_id", referencedColumnName = "productCode")
private List<Supplier> suppliers;
}
Supplier entity
#Entity
public class Supplier {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
private String name;
}
Unidirectional #OneToMany association:
#Entity
public class Product {
#Id
// #Column(name = "id") maybe
// #GeneratedValue maybe
private String productCode;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) // according to your need
private List<Supplier> suppliers;
...
}
And,
#Entity
public class Supplier {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
...
}
#ManyToOne association:
#Entity
public class Product {
#Id
// #Column(name = "id") maybe
// #GeneratedValue maybe
private String productCode;
...
}
And,
#Entity
public class Supplier {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "product_id", foreignKey = #ForeignKey(name = "PRODUCT_ID_FK"))
private Product product;
private String name;
...
}
Student.java
#Entity
#Table(name = "Student")
#Data
#NoArgsConstructor
public class Student implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "studentId", cascade = CascadeType.ALL)
private List<Subject> subjectList = new ArrayList<>();
public void addSubject(Subject subject) {
subjectList.add(subject);
subject.setStudentId(this);
}
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
}
Subject.java
#Entity
#Table(name = "Subject")
#Data
#NoArgsConstructor
public class Subject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="studentId", nullable = false)
private Student studentId;
#Column(name = "subjectName")
private String subjectName;
#Column(name = "subjectCode")
private int subjectCode;
}
SubjectRepository.java
#Repository
public interface SubjectRepository extends JpaRepository<Subject, Long> {
}
As shown in the code structure above, I have 2 entities (Student, Subject) and a repository class (SubjectRepository). When i try to save into the Subject table, somehow the student name "Thomas" from the Student table gets updated as well in the database. I would like to only insert into Subject table without having any values from the Student table getting updated. Need some help on this. Thanks!
public static void main(String[] args) {
#Autowired protected SubjectRepository subjectRepository;
Student student = new Student();
student.setFirstName("Thomas");
Subject subject = new Subject();
subject.setSubjectName("Chemistry");
subject.setSubjectCode(12345);
student.addSubject(subject)
subjectRepository.save(subject)
}
I would like to only insert into Subject table without having any values from the Student table getting updated
You can achieve this with following code :
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="studentId", nullable = false, updatable = false)
private Student studentId;
When using Spring JPA I would suggest using the JpaRepository API. You just need to pass in your entity, and it should save as desired.
Ex:
subjectRepository.save(subject);
You have try this
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
#JoinColumn(name="studentId", nullable = false, updatable = false)
private Student studentId;
#MaxExplode You have to use cascade = CascadeType.REFRESH then other details will not update. but if you are try to set updateStudent.setfirstNamr(student.getFirstName()); and then save parent object then i will update. otherwise it will not update.
I have below 1-m relationship on entities which Mentor to Students. The mentor has composite primary key which i use as foreign key in student
#Entity
public class Mentor implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private MentorPK id;
private String email;
#OneToMany(mappedBy="mentor")
private Set<Student> students;
public MentorPK getId() {
return id;
}
//getters and setters
}
#Embeddable
public class MentorPK implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String add;
//getters and setters
//override equals and hashcode
}
#Entity
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
#ManyToOne
#MapsId("id")
#JoinColumns({
#JoinColumn(name="name_fk", referencedColumnName="name"),
#JoinColumn(name="address_fk", referencedColumnName="address")
})
private Mentor mentor;
//Getters and setters
}
I then persist the above as below but only the mentor is persisted where student table is empty.
How can I persist the mentor with students?
Set<Student> students = new HashSet<Student>();
Student s1 = new Student();
s1.setName("Student 1");
Student s2 = new Student();
s2.setName("Student 2");
students.add(s1);
students.add(s2);
MentorPK mpk = new MentorPK();
mpk.setAddress("C");
mpk.setName("D");
Mentor m = new Mentor();
m.setId(mpk);
m.setEmail("emaill");
m.setStudents(students);
studentManager.saveMentor(m);
Try changing annotation of students field to
#OneToMany(mappedBy="mentor", cascade = CascadeType.PERSIST)
When you use a composite-key, mapped as an Embeddable you need to use #EmbeddedId:
#Entity
public class Mentor {
#EmbeddedId
private MentorPK id;
private String email;
#OneToMany(mappedBy="mentor")
private Set<Student> students;
public MentorPK getId() {
return id;
}
//getters and setters
}
and the Student becomes:
#Entity
public class Student {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
#ManyToOne
#JoinColumns({
#JoinColumn(name="name_fk", referencedColumnName="name"),
#JoinColumn(name="address_fk", referencedColumnName="address")
})
private Mentor mentor;
//Getters and setters
}
The #MapsId is used when both the #Id and the #ManyToOne share the same database columns, which is not your case, since you have a numeric identifier and a composite foreign-key.
You may need to create the reference from Student to Mentor in each Student.
So in your code, after you create m you need to:
s1.setMentor(m);
s2.setMentor(m);
Otherwise Hibernate may not know what to populate columns name_fk and address_fk with.
How about changing:
#OneToMany(mappedBy="mentor")
private Set<Student> students;
to:
#OneToMany(mappedBy="mentor")
private Set<Student> students = new HashSet();
or
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="student_id")
#org.hibernate.annotations.IndexColumn(name="idx")
private Set<Student> students = new HashSet();
also try not to skip
= new HashSet();
part
As I understand your request, you would like to have the Mentor be the owner of the relationship. You do not obtain this with the line #OneToMany(mappedBy="mentor"). This actually puts the Student as the owner of the relation.
I have tested this domain model and did a few modifications to the annotations in order to have the test code work as you expect.
Student
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int id;
private String name;
#ManyToOne
#JoinColumns({
#JoinColumn(name="name_fk", referencedColumnName="name", insertable = false, updatable = false),
#JoinColumn(name="address_fk", referencedColumnName="address", insertable = false, updatable = false )
})
private Mentor mentor;
//setters and getters
}
Mentor
public class Mentor implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private MentorPK id;
private String email;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name="name_fk", referencedColumnName="name"),
#JoinColumn(name="address_fk", referencedColumnName="address")
})
private Set<Student> students;
//setters and getters
}
It even works without doing:s1.setMentor(m);s2.setMentor(m);. I did not expect it but it seems that hibernate is dealing with this.
A related article is here.
Attention: drop the database tables after you change the annotations in order to allow hibernate to recreate the tables.
I have two tables which have Many-to-Many relations which have a JoinTable USER_SERVICES as below.
#Entity
public class User implements Serializable {
#NotNull
#Column(unique=true)
private String username;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "USER_SERVICES",
joinColumns = {#JoinColumn(name = "id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "", referencedColumnName = "name")})
private Set<Services> services;
// Getters and Setters
}
#Entity
public class Services implements Serializable {
#NotNull
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long serviceId;
#NotNull
#Column(unique=true)
private String name;
//Getters and Setters
}
The above code creates a table USER_SERVICES, but I also want to have a Many-to-Many relation on the table USER_SERVICES with another table RATINGS which would result in another table USER_SERVICES_RATINGS. how can I define this relation with Hibernate/JPA annotations?
Bi-Directional Many to Many using user managed join table object (Relatively common)
Commonly used when you want to store extra information on the join object such as the date the relationship was created.
public class Foo{
private UUID fooId;
#OneToMany(mappedBy = "bar", cascade=CascadeType.ALL)
private List<FooBar> bars;
}
public class Bar{
private UUID barId;
#OneToMany(mappedBy = "foo", cascade=CascadeType.ALL)
private List<FooBar> foos;
}
#Entity
#Table(name="FOO_BAR")
public class FooBar{
private UUID fooBarId;
#ManyToOne
#JoinColumn(name = "fooId")
private Foo foo;
#ManyToOne
#JoinColumn(name = "barId")
private Bar bar;
//You can store other objects/fields on this table here.
}
You need to create an explicit UserServices entity and setup the relationship to the Ratings entity per your needs.
Remember that in hibernate you model relationships between entities (i.e. your java objects), not db tables.