How to implement bidirectional hibernate relationship correctly? - sql

#Entity
#Table(name = "project")
public class Project {
#Id
#Column(name = "project_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#OneToOne
#JoinColumn(name = "idea_id", referencedColumnName = "idea_id")
#JsonIgnore
private Idea idea; .......}
And
#Entity
#Table(name = "idea")
public class Idea {
#Id
#Column(name = "idea_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Size(max = 240)
#NotNull
private String description;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "project_id", referencedColumnName = "project_id")
private Project project; ..........}
What is wrong with my hibernate relationships in these two classes? This is example of relationship that I want to implement.
And this is actual tables that I get with these relationships:
Idea table:
And Project table:
How to get rid of null values in idea_id column in project table?

Related

ORM: EclipseLink AssociationOverride "Persistent type of override attribute cannot be resolved"

I am building an application that has a database of students, courses, and it also keeps track of all the courses that each student is taking,
I have an entity for Course and Student, and they have a one to many relationship with entity StudentCourses and an embeddable class of StudentCoursesID.
In the StudentCourse when I try to use the annotation AssociationOverride it gives me a problem saying
"Persistent type of override attribute "student" cannot be resolved"
"Persistent type of override attribute "course" cannot be resolved"
and
"Embedded ID class should not contain relationship mappings"
I dont understand if i did the mapping wrong or if there is a disconnection between my entities and classes.
Below I have each of the the entity starting with StudentCourses which is giving me issues.
StudentCourses
package jpa.entitymodels;
import javax.persistence.*;
#Entity
#Table(name = "student_courses")
#AssociationOverrides({
#AssociationOverride(name = "student", joinColumns = #JoinColumn(name = "sEmail")),
#AssociationOverride(name = "course", joinColumns = #JoinColumn(name = "cId"))
})
public class StudentCourses {
private StudentCoursesId id = new StudentCoursesId();
public StudentCourses() {
}
public StudentCourses(StudentCoursesId id) {
this.id = id;
}
#EmbeddedId
public StudentCoursesId getId() {
return id;
}
StudentCoursesId
package jpa.entitymodels;
import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;
import java.io.Serializable;
#Embeddable
public class StudentCoursesId implements Serializable {
private static final long serialVersionUID = 1L;
private Student student;
private Course course;
public StudentCoursesId() {
}
#ManyToOne
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
#ManyToOne
public Course getCourse() {
return course;
}
Course
package jpa.entitymodels;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
#Entity
#Table(name = "course")
public class Course {
#Id
#Column(name = "id")
int cId;
#Column(name = "name")
String cName;
#Column(name = "instructor")
String cInstructorName;
#OneToMany(mappedBy = "id.course", fetch = FetchType.LAZY)
List<StudentCourses> studentCourses = new ArrayList<>();
Student
package jpa.entitymodels;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
#Entity
#Table(name="student")
public class Student {
#Id
#Column(name = "email")
String sEmail;
#Column(name = "name")
String sName;
#Column(name = "password")
String sPass;
#OneToMany(mappedBy = "id.student", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
List<StudentCourses> studentCourses = new ArrayList<>();
The 'student' doesn't exist in StudentCourses which is why you get the error. Overrides you want to apply to the embeddable need to be defined on the embeddable mapping, not the StudentCourses class.
#Entity
#Table(name = "student_courses")
public class StudentCourses {
#Embedded
#AttributesOverride({
#AttributeOverride(name = "student", joinColumns = #JoinColumn(name = "sEmail")),
#AttributeOverride(nname = "course", joinColumns = #JoinColumn(name = "cId"))})
private EmbeddableClass embeddableClass;
public StudentCourses() {
}
}
JPA requires an ID class that has the simple pk types within it (or other nested composite PK classes, not relationships), requiring StudentCoursesId have a int/string property for the cId and sEmail. If you want to have mappings to course/student, maybe see the mapsId annotation or alternatively, I would map it like this:
#Entity
#Table(name = "student_courses")
#IdClass(StudentCoursesId.class)
public class StudentCourses {
#Id
#JoinColumn(name = "sEmail")
Student student;
#Id
#JoinColumn(name = "cId")
Course course;
}
public class StudentCoursesId implements Serializable {
private static final long serialVersionUID = 1L;
private String student;//Name matches id property in StudentCourses
private int course;
}

JPA Query mapping

I want to use orderNumber in ProductRepository but I keep getting SQL error. I mapped both sides.
this is product entity.
#Entity
public class Product extends BaseEntity {
#Id
#GeneratedValue
#Column(name = "product_id")
private Long id;
#ManyToOne
#JoinColumn(name = "orderItem_id")
private OrderItem orderItem;
this is orderItem entity.
#Entity
public class OrderItem extends BaseEntity {
#Id
#GeneratedValue
#Column(name = "orderItem_id")
private Long id;
private String orderNumber
#OneToMany(mappedBy = "orderItem", cascade = CascadeType.ALL, orphanRemoval = true)
#Builder.Default
private List<Product> products = new ArrayList<Product>();
this is query in ProductRepository.
#Query(value = "SELECT * FROM OrderItem a, Product b WHERE a.orderItem_id = b.orderItem_id", nativeQuery = true)
Product findByOrderNumber(String orderNumber);
Alternatively, you can try query by a method as shown below, you don't need to use the #Query in this case.
ProductRepository
Product findByOrderItemOrderNumber(String orderNumber);
you can find more details here

Spring boot JPA - primary key of entities in database

I have #OneToMany and #ManyToOne relationship between parent and child entities.
#Entity
#Table(name = "parent")
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#OneToMany(targetEntity=Measurement.class, mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
#JsonManagedReference
private List<Child> children = new ArrayList<>();
}
and I have child entity like this
#Entity
#Table(name = "child")
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(targetEntity=Parent.class, fetch = FetchType.LAZY)
#JoinColumn(name = "parent_id")
#JsonBackReference
private Parent parent;
After saving this data, the database looks like following,
Parent:
id
1
Child
id parent_id
2 1
my question is, why does the primary key of child is 2 and not 1? In the child table, it could have a primary key as 1 and foreign key reference to parent as 1. When I add one more parent, then the tables looks like this,
Parent:
id
1
3
Child
id parent_id
2 1
4 3
Am I doing something wrong or it is the expected behaviour?
The generation strategy #GeneratedValue(strategy = GenerationType.AUTO) will takes value from the default hibernate sequence, so the same sequence is used for all key generation.
When you are inserting the data, it inserts in the sequence like Parent then Child, as it is getting values from the same sequence generator, it will increase in sequence for all your table.
You need to use the GenerationType.IDENTITY strategy for your purpose.
In parent Parent
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
In child
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

Making SQL/JPQL query to select all topics that matches both keywords

Challenge:
I want to create a query that selects Topics that match both the keyword ID´s "Java" and "sql", the Topic with ID = 1 matches both keywords "Java" and "Sql.
I have implemented two simple entities Topic and Keyword. They have a bidirectional ManyToMany relationship:
#Entity
#Table(name = "Topic")
public class Topic implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "topicID")
private Long id;
#Column(name = "topicTitle")
private String title = "";
#ManyToMany
#JoinTable(name = "Join_Topic_Keyword",
joinColumns = #JoinColumn(name = "Topic_ID"),
inverseJoinColumns = #JoinColumn(name = "Keyword_ID"))
private Set<Keyword> keywords;
}
#Entity
#Table(name = "Keyword")
public class Keyword implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "keywordID")
private String id;
#ManyToMany(mappedBy = "keywords")
private Set<Topic> topics;
}
Here is the structure table.
And This is the result from Join_Topic_Keyword

Multiple unidirectional oneToMany relationship columns from one table to another table in JPA

I'm trying to have a localization table that is linked to from multiple tables.
I'm realizing that the problem is that I'm using the ID of Localization (eg Localization_Id) so I can't link to different localizations without some other key. Should I use a join table or some other sequential id in the database somehow? Not sure what the best approach is using JPA.
Thanks in advance.
#Entity
public class MyEntityWithLocalization {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id;
#OneToMany(fetch = FetchType.EAGER, cascade={CascadeType.ALL})
#JoinColumn(name="LOCALIZATION_KEY")
List<Localization> field1;
#OneToMany(fetch = FetchType.EAGER, cascade={CascadeType.ALL})
#JoinColumn(name="LOCALIZATION_KEY")
List<Localization> field2; //can't be unique from field one as it links to the MyEntityWithLocalization id.
#OneToMany(fetch = FetchType.EAGER, cascade={CascadeType.ALL})
#JoinColumn(name="LOCALIZATION_KEY")
List<Localization> field3; //can't be unique from field one as it links to the MyEntityWithLocalization id.
}
#Entity
public class Localization {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id;
String language;
String string;
public Localization(String language, String string) {
this.language = language;
this.string = string;
}
public Localization(){
}
}
This creates a localization_key in the localization table but that is just keyed to the ID of the MyEntityWithLocalization - it needs to be another unique value which makes me believe a join table may make sense in this case.
create table localization (
id number(19,0) not null,
language varchar2(255),
string varchar2(255),
localization_key number(19,0),
primary key (id)
);
Hmm. Why not just split the entity into constant and localizable part? Something like this:
#Entity
class MyEntity{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id;
#OneToMany
#MapKeyColumn
Map<String, MyEntityLocalization> localizations;
}
#Embeddable
class MyEntityLocalization {
String field1;
String field2;
String field3;
}
Where the localizations field has the map from the language to the localization? The other way is using Hibernate-specific annotations:
#Entity
class MyEntityWithLocalization {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id;
#OneToMany
#MapKeyColumn(name="language")
#WhereJoinTable(clause = "key=1")
Map<String, String> field1;
#OneToMany
#MapKeyColumn(name="language")
#WhereJoinTable(clause = "key=2")
Map<String, String> field2;
}
#Entity
public class Localization {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id;
long key;
String language;
String string;
}