undirectional one to one mapping with forein key in supplementary table? - java

I have two tables with one to one relationship b/w student and address table
Student
student_id
name
Address
address_id
student_id(foreign key to student_id in student table)
...
Here is the relevant entity section
#Entity
#Table(name = "STUDENT")
public class Student {
#Id
#GeneratedValue
#Column(name = "STUDENT_ID")
private long id;
#OneToOne
private Address address;
}
#Entity
#Table(name = "ADDRESS")
public class Address {
#Id
#GeneratedValue
#Column(name = "ADDRESS_ID")
private long id;
private long student_id;
}
I want to keep the foreign key i.e. student_id(foreign key to id in student table) under address table as shown in table structure at top but
want to keep the undirectional association of private Address address under student entity. I am not sure how to achieve it ?
what I tried is this
#Entity
#Table(name = "STUDENT")
public class Student {
#Id
#GeneratedValue
#Column(name = "STUDENT_ID")
private long id;
#OneToOne(mappedBy ="student_id")
private Address address;
}
#Entity
#Table(name = "ADDRESS")
public class Address {
#Id
#GeneratedValue
#Column(name = "ADDRESS_ID")
private long id;
#OneToOne
#JoinColumn(name="student_id")
private long student_id;
}
But it gives below exception
#OneToOne or #ManyToOne on Address.student_id references an unknown entity: int
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:107)
at org.hibernate.cfg.Configuration.processEndOfQueue(Configuration.java:1580)
at
It works as soon as I make association bidirectional with
private Student student_id instead of private long student_id
So in a way Hibernate forcing me to make association bidirectional when foreign key exist in supplementary table(in this case address table)

Related

OneToMany mapping on table with composite key returns empty list

I have been struggled into OneToMany mapping on entity with composite primary key when I try to get List of items of child table.
I have entitties Person and PhoneNumbers. One person may have multiple phone numbers. PhoneNumber entity have primary key consist of two fields: id and person_id which is foreign key to Person entity.
This is a database schema:
person:
id (pk)
person_name
phone_number:
id (pk)
person_id (pk)(fk)
phone_number
Person class
#Entity(name = "person")
public class Person {
#Id
#Column(name = "id")
private Long id;
#Column(name = "person_name")
private String name;
#OneToMany(mappedBy = "person")
private List<PhoneNumber> phoneNumbers;
// constructor, getters, setters...
}
PhoneNumber class
public class PhoneNumber {
#EmbeddedId
private PhoneNumberPk phoneNumberPk;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id", insertable = false, updatable = false)
private Person person;
#Column(name = "phone_number")
private String phoneNumber;
// constructor, getters, setters...
}
PhoneNumberPk class
#Embeddable
public class PhoneNumberPk {
#Column(name = "id")
private Long id;
#Column(name = "person_id")
private Long personId;
// constructor, getters, setters...
}
Problem is when I get Person entity from database and call person.getPhoneNumbers() I always get empty list. Hibernate debugging shows that query that fetch data from phone_number table is executed when I call person.getPhoneNumbers() but I always get empty list.
I'm using Spring Boot - Spring Data JPA 2.0.7 and Hibernate 5.2.17

One-to-One association with composite ID of owner Entity

I have a to make a one-to-one association between two Entities, but one of them must have two #Id. One is PRI another one is MUL. How must i declare composite id, and how do i need to map the classes?
#Entity
#Table(name = "PERSONS")
public class Person implements Serializable{
private static final long serialVersionUID = -3451407520028311143L;
#Id
#Column(name = "ID")
private Integer id;
#Column(name = "ADDRESS_ID")
private Integer addressId;
#Column(name ="NAME")
private String name;
#OneToOne(mappedBy= "person", cascade= CascadeType.ALL)
private Address address;
...
}
second class is mapped via #IdClass annotation
#Entity
#Table ( name = "ADDRESS" )
#IdClass(AddressKeys.class)
public class Address implements Serializable {
#Id
#Column ( name = "ID")
private Integer id;
#Id
#Column ( name = "PERSON_ID")
private Integer idPerson;
#Column ( name = "CITY" )
private String city;
#OneToOne(cascade= CascadeType.ALL)
#JoinColumn(name="PERSON_ID")
private Person person;
...
}
and the id class
class AddressKeys implements Serializable{
private Integer id;
private Integer idPerson;
//getters and setters
#Override
public int hashCode() {
...
return result;
}
#Override
public boolean equals(Object obj) {
...
}
}
So when i try to create and save a record i have a next error
Could not open sessionRepeated column in mapping for entity:
hibernateMappedModels.base1.mappedClasses.oneToOne.Address column:
PERSON_ID (should be mapped with insert="false" update="false")
java.lang.NullPointerException at
hibernateMappedModels.base1.Main.run(Main.java:45) at
hibernateMappedModels.base1.Main.main(Main.java:24
I tryed to make an Id fields unInsertable and unUpdatable, and it was working, but i need them to be insertable and updatable; Is there any possibility to do it?
I am confused by your mappings and not sure what is required other then the simple mappings below: if I am missing something then you will need to expand on your question. You are getting the error as you have mapped the column twice - once via the one-to-one and once as a simple property. Additionally, I am not sure why you require a composite key on address.
#Entity
#Table(name = "PERSONS")
public class Person implements Serializable{
private static final long serialVersionUID = -3451407520028311143L;
#Id
#Column(name = "ID")
private Integer id;
#Column(name ="NAME")
private String name;
#OneToOne(mappedBy= "person", cascade= CascadeType.ALL)
private Address address;
}
#Entity
#Table ( name = "ADDRESS" )
public class Address implements Serializable {
#Id
#Column ( name = "ID")
private Integer id;
#Column ( name = "CITY" )
private String city;
#OneToOne(cascade= CascadeType.ALL)
#JoinColumn(name="PERSON_ID")
private Person person;
}

How to setup JPA Entity classes?

I am struggling with how to setup my JPA entity classes and which annotations should go where
I have the following tables:
Table Customer {
id: primary key,
name
}
Table CustomerDimension {
id: primary key, foreign key(Customer.id),
detail
}
Currently I have the following entity classes:
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#OneToOne
private CustomerDimension customerDimension;
}
public class CustomerDimension {
// ? what is meant to go here?
private long id;
#Column(name = "detail")
private String detail;
}
What annotation is meant to go on CustomerDimension.id to allow me to insert a new Customer that has a new CustomerDimension?
Should CustomerDimension also have a reference back to Customer?
Table Customer {
id: primary key,
name
}
Table CustomerDimension {
id: primary key,
foreign key(Customer.id),
detail
}
CustomerDimension is the owning side. so, the #OneToOne mapping should be like
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
}
public class CustomerDimension {
#Id
private long id;
#Column(name = "detail")
private String detail;
#OneToOne
private Customer customer;
}
You have the following problems :
Customer and CustomerDimension need the annotation #Entity.
In your DDL, the table CustomerDimension has a foreign key on Customer. Hence, the #OneToOne relationship should be declared on CustomerDimension's side.
Still in the DDL, your foreign key does not have an explicit name. I will assume it is customer_id and use it to declare the #JoinColumn (see below)
#Column annotations are required only if you need the column to have a name which is different from the attribute's name (but you can keep them for clarity).
Here is how I would map it.
#Entity
#Table(name = "Customer") //Optional
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "name") //Optional
private String name;
}
And for CustomerDimension :
#Entity
#Table(name = "CustomerDimension") //Optional
public class CustomerDimension {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "detail") //Optional
private String detail;
#OneToOne
#JoinColumn(name = "customer_id") //NOT optional
private Customer customer
}
EDIT (answer to your comment) :
If you really want your FK to be the primary key, you can do it like this :
#Entity
#Table(name = "CustomerDimension") //Optional
public class CustomerDimension {
#Column(name = "detail") //Optional
private String detail;
#Id
#OneToOne
#JoinColumn(name = "id") //NOT optional
private Customer customer
}
I still wonder why you do not put all information in the same table. It would save you a SQL join.
What you have here is a OneToMany biidirectional relationship with a foreign key instead of a join table. A join table seems to be preferred by vendors, but it's OK.
So, you have a list (or set) of CustomerDimensions in Customer, but with the mappedBy value set.
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy="customer")
List<CustomerDimensions> dimensions;
}
and
public class CustomerDimension {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "detail")
private String detail;
#ManyToOne
Customer customer;
}
It's natural that Customers have a set of dimensions. By having a bidirectional mapping, if you have a dimension, then you can look up the customer easy (just reference the customer field)
EDIT: Since the CustomerDimension table has a Customer id reference, you can select many CustomerDimensions for one Customer, hence a OneToMany relationship. In order to set the CustomerDimension.customer_id field, simply put a CustomerDimension in the Customers list of dimensions.

How to define the association table as pojo entity

I have 3 tables in the db. I am trying to write the JPA entities. I am facing some issues with Association table entity. My entities are as follows,
Person.java
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
private Long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
//setter and getter
}
Exam.java
#Entity
#Table(name = "exam")
public class Exam {
#Id
#GeneratedValue
private long examId;
#Column(nullable = false)
private String examName;
#Column(nullable = false)
private int marks;
//Setters and getters
}
The table structure for association table is,
create table person_exam (
personId BIGINT not null,
examId BIGINT not null,
primary key (personId, examId)
);
I tried the association table entity with #ManyToMany annotation for both the properties which is not giving me the result.
Can anyone please suggest me what should I need to use (ManyToMany/OneToOne/ManyToOne/OneToMany ) in my entity for the above person_exam table.
from the PRO JPA 2nd Ed. book:
the only way to implement a many-to-many relationship is with a separate join table. The consequence of not having any join columns in either of the entity tables is that there is no way to determine which side is the owner of the relationship. Because every bidirectional relationship has to have both an owning side and an inverse side, we must pick one of the two entities to be the owner.
So I chose the the Person entity. Applying the needed changes to your incomplete code:
#Entity
#Table(name = "person")
public class Person {
#Id
#GeneratedValue
private Long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
/**
* we need to add some additional metadata to the Person designated
* as the owner of the relationship, also you must fully specify the names of
* the join table and its columns because you already provided a schema
* for the association table, otherwise the JPA provider would generate one.
*/
#ManyToMany
#JoinTable(name="person_exam",
joinColumns=#JoinColumn(name="personId"),
inverseJoinColumns=#JoinColumn(name="examId"))
private Collection<Exams> exams;
//setter and getter
}
#Entity
#Table(name = "exam")
public class Exam {
#Id
#GeneratedValue
private long examId;
#Column(nullable = false)
private String examName;
#Column(nullable = false)
private int marks;
//Setters and getters
/**
* As in every other bidirectional relationship,
* the inverse side must use the mappedBy element to identify
* the owning attribute.
*/
#ManyToMany(mappedBy="exams")
private Collection<Person> people;
}

Hibernate Mapping when foreign key placed in reference class

I have two classes Student and Address.
Student{
stuid,
stuName,
}
Address{
street,
city,
stuid;//foriegn key Ref with Studnet
}
Can any one help me to map these two classes using hibernate??
You should learn what is OneToOne mapping in hibernate firstly.
Secondly if I would want to design then I would have address_id as foreign key in Student table and not student id.
//Table name will be taken as Student as you are not specifying it using #Table annotation
Student class
#Entity
public class Student{
#Id
#Column("stuid")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column("stuName")
private String name;
//setters and getters
}
Address class
#Entity
public class Address{
#Id
#Column("add_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column("street")
private String street;
#Column("city")
private String city;
#OneToOne(cascade={CascadeType.SAVE,CascadeType.MERGE})
#JoinColumn(name="stuid")
private Student student
//setters and getters
}
Suppose if a Student can have multiple Address entities then you need to have one-to-many relationship between Student and Address classes. A student should know what addresses they belong to and also as you need to save the student id in address table then the relationship becomes bi-directional.
The entities looks like this:
Student.java
#Entity
#Table(name = "student_tbl") // Optional, By default table name is student, if you want to give different name then use this line.
public class Student1 {
#Id
#GeneratedValue
private int stuid;
private String stuName;
#OneToMany(mappedBy = "student")
private List<Address> address = new ArrayList<Address>();
// Setters & Getters
}
Address.java
#Entity
#Table(name = "address_tbl")
public class Address {
#Id
#GeneratedValue
private int addressId;
private String street;
private String city;
#ManyToOne
#JoinColumn(name="stuid")
private Student1 student;
// Setters & Getters
}

Categories