I have two tables:
Person
ID | NAME | EMAIL_ID (foreign key of Email.ID)
Email
ID | EMAIL_ADDRESS
I need to pull back the data into the following Entity but I am unsure how to join PERSON.EMAIL_ID with EMAIL.ID using annotations
#Entity
#Table(name = "PERSON")
public class PersonEntity {
#Column(name = "ID")
private String id;
#Column(name = "NAME")
private String name;
// How do I do a one to one join here?
private String emailAddress;
}
How can I use annotations properly so that the emailAddress field maps to the EMAIL.EMAIL_ADDRESS column?
Your Person entity should join with the Email entity and not the emailAddress property directly.
#Entity
#Table(name = "PERSON")
public class PersonEntity {
#Column(name = "ID")
private String id;
#Column(name = "NAME")
private String name;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "person", cascade = CascadeType.ALL)
private Email email;
}
But it is strange to have an entity only for emails. Do you only ensure email is unique ? In this case Person entity can have an emailAddress with #Column(unique = true).
#Entity
#Table(name = "PERSON")
public class PersonEntity {
#Column(name = "ID")
private String id;
#Column(name = "NAME")
private String name;
#Column(unique = true)
private String emailAddress;
}
You usually don't do joins in Hibernate. Rather use mapping and HQL.
A good example can be found here :
http://viralpatel.net/blogs/hibernate-one-to-one-mapping-tutorial-using-annotation/
Related
Using Hibernate, I have created two entities - Employee and EmployeeDetails. Since EmployeeDetails cannot exist without a corresponding entry in Employee, I figured I don't need an extra ID for EmployeeDetails, but could instead use the ID of the Employee entity. Here is how I have implemented this idea:
Employee-Entity:
#Entity
#Table(name = "employees")
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#OneToOne(cascade = CascadeType.ALL)
EmployeeDetails employeeDetails;
}
Employee-Details-Entity:
#Entity
#Table(name = "employee_details")
#Data
public class EmployeeDetails {
#Id
private Long id;
#Column(name = "address")
private String address;
#Column(name = "e_mail", nullable = false)
private String eMail;
#Column(name = "phone")
private String phone;
#MapsId
#OneToOne(mappedBy = "employeeDetails", cascade = CascadeType.ALL)
#JoinColumn(name = "employee_id")
private Employee employee;
}
By adding the #MapsId annotation to the employee-variable inside EmployeeDetails, I should be assigning the primary key of the Employee-entity to the Id-column of EmployeeDetails.
In a second step, I have written some data into both of my tables.
employee table in MySQL database:
employee_id first_name last_name employee_details_employee_id
1 John Smith null
2 Jennifer Adams null
The last column was somehow generated by Hibernate. I don't understand why. It appears to be some column for identification, but I don't need it.
employee_details table in MySQL database:
employee_id address e_mail phone
1 null john.smith#gmail.com null
2 null jennifer.adams#gmail.com null
I have only assigned an e-mail to the employees. Surprisingly, there is no employee-entry in this database table. I don't really need it anyways, but I was expecting it. So yeah, I think I am doing something terribly wrong and would really appreciate some help.
Change mappedBy side, here useful links
https://vladmihalcea.com/change-one-to-one-primary-key-column-jpa-hibernate/
https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/
https://javabydeveloper.com/one-one-bidirectional-association/
#Entity
#Table(name = "employees")
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#OneToOne(mappedBy = "employee", cascade = CascadeType.ALL)
EmployeeDetails employeeDetails;
}
Entity
#Table(name = "employee_details")
#Data
public class EmployeeDetails {
#Id
private Long id;
#Column(name = "address")
private String address;
#Column(name = "e_mail", nullable = false)
private String eMail;
#Column(name = "phone")
private String phone;
#MapsId
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "employee_id")
private Employee employee;
}
#MapId is not a popular solution in work with Hibernate.
Maybe in your case, #Embeddable will be a better option?
If I understand correctly, EmployeeDetails cannot exist without correlated Employee. So, EmployeeDetails could be a field in Employee as an embeddable field:
#Entity
#Table(name = "employees")
#Data
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#Embedded
EmployeeDetails employeeDetails;
}
Then EmployeeDetails doesn't need ID and relation with the employee:
#Embeddable
public class EmployeeDetails {
#Column(name = "address")
private String address;
#Column(name = "e_mail", nullable = false)
private String eMail;
#Column(name = "phone")
private String phone;
}
As you can see, now in the database it's only one table employees, but in our hibernate model, we have two separated objects. Probably you don't need EmployeeDetails without Employee entity, so there is more efficient construction.
If you really need a separated table for EmployeeDetails with relation to Employee I recommend creating standard one-to-one mapping instead of #MapId construction.
I have two entities which is giving me error on creation of datasource
Entity1
#NoArgsConstructor
#Entity
#Table(name = "person_details")
public class PersonDetails {
#Id
private String pid;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "exist_flag")
private String existFlag;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "pid", nullable = false)
private List<AddressDetails> addressDetails;
}
Entity 2 | EDIT 1
#Data
#NoArgsConstructor
#Entity
#Table(name = "address_details")
public class AddressDetails {
private String street;
#Column(name = "address_exist_flag")
private String addressExistFlag;
#ToString.Exclude
#EqualsAndHashCode.Exclude
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "pid", insertable = false, updatable = false)
private PersonDetails personDetails;
}
Getting error as below:
I am getting error as "No identifier specified for entity: AddressDetails".
How to resolve in such case? Can we use spring data jpa having OneToMany mapping in such case where one entity do not have primary key ?
The error you are getting is because you are using the same column name for 2 different columns.
#Id
private String pid;
and
#JoinColumn(name = "pid"
means that you want both your id column and your foreign key column to be named "pid", hence the error. I would suggest using a name like "addressDetailsFk" for the JoinColumn attribute.
i have two tables Person and PersonType and there is a relation "ManyToMany" between these tables. During loading my application i am getting all the PersonTypes, but when i create new Person, i have an exception
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "person_type_person_type_name_key"
Detail: Key (person_type_name)=(TYPE1) already exists.
person_type_person_type_name_key is my table where i should store the relations between Person and PersonType. When i create a new Person i DO NOT want to insert into PersonType table because the person type already exists. What should i do, not to insert into DB ? I am using personService.save(person); which is trying to insert also in person_type table into DB.
#Table(name = "person")
public class Person {
#Id
#Column(name = "id")
#GeneratedValue(generator = "person_id_seq")
#SequenceGenerator(sequenceName = "person_id_seq", name = "person_id_seq", schema = "manager", allocationSize = 1, initialValue = 1)
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "password")
private String password;
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(
name = "person_person_types",
joinColumns = #JoinColumn(name = "person_fk"),
inverseJoinColumns = #JoinColumn(name = "person_type_fk"))
private List<PersonType> personTypes;
}
#Entity
#Table(name = "person_type")
public class PersonType {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "person_type_name", unique=true)
private String personType;
#ManyToMany(mappedBy = "personTypes", cascade = {CascadeType.ALL})
private Set<Person> persons;
}```
Maybe the problem is with inserting the PersonType. Ensure that you put PersonType with the same ID and same name into the DB. Also change CascadeType.ALL to be CascadeType.MERGE
I want to join only one column from another table.
I have 2 entities now:
#Entity
public class Message {
....
#ManyToOne
#JoinColumn(name = "ATTRIBUTE_ID")
private Attribute attribute;
}
#Entity
#Table(name = "ATTRIBUTE_TABLE")
public class Attribute {
#Id
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
}
And I want to simplify code and don't use entity for only one column:
#Entity
#SecondaryTable(name = "ATTRIBUTE_TABLE", pkJoinColumns =
#PrimaryKeyJoinColumn(name = "ID", referencedColumnName = "ATTRIBUTE_ID")),
public class Message {
....
#Column(table = "ATTRIBUTE_TABLE", name = "NAME")
private String attribute;
}
But #SecondaryTable JoinColumn cannot reference a non-primary key.
How to add a column from another table without using additional entity for it?
I'm creating a MySQL database as followed :
database design
the Country and Province tables are pre-filled with data. I have the application running and can get stuff no problem, and also the join table person_has_address works when getting.
however, when I insert data using post I want to be able to set the ID of the province, and let spring data jpa just add that number to add_pro_id in the Address table. For example, when I post the following json:
{ "firstName":"bilbo", "lastName":"baggings", "address":{"street":"streetName", "streetNum":3, "zipcode":"1337GG", "city":"TheCity", "province":{"name":"aProvinceName"}} }
jpa should see that aProvinceName exists and grab that id and add that to add_pro_id.
Now it just insert aProvinceName as new value in province and add the new id to add_pro_id.
The person class:
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="per_id")
private int id;
#Column(name="per_name")
private String firstName;
#Column(name="per_surname")
private String lastName;
#Column(name="per_birth_date")
private String birthDate;
#Column(name="per_fax")
private String fax;
#Column(name="per_phone")
private String phone;
#Column(name="per_email")
private String email;
#OneToOne(optional = false, cascade = CascadeType.ALL)
#JoinTable(name="person_has_address", joinColumns = {#JoinColumn(name="pha_per_id", referencedColumnName = "per_id")}, inverseJoinColumns = {#JoinColumn(name="pha_add_id", referencedColumnName = "add_id")})
private Address address;
// getters and setters
This is the person repository:
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(#Param("name") String name);
}
This is the address class:
#Entity
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="add_id")
private int id;
#Column(name = "add_street")
private String street;
#Column(name="add_street_num")
private int streetNum;
#Column(name="add_zip")
private String zipcode;
#Column(name="add_city")
private String city;
#JoinColumn(name="add_pro_id", referencedColumnName = "pro_id")
#ManyToOne(optional=false, cascade = CascadeType.ALL)
private Province province;
// getters and setters
Province class:
#Entity
public class Province {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="pro_id")
private int id;
#Column(name="pro_name")
private String name;
#ManyToOne
#JoinColumn(name="pro_cou_id")
private Country country;
// getters and setters
And lastly country class:
#Entity
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="cou_id", insertable = false, updatable = false)
private int id;
#Column(name="cou_name", insertable = false, updatable = false)
private String name;
// getters and setters
I've tried adding insertable = false and updatable = false, but the application then just inserts NULL values in my database. I've also tried working with #primarykeyjoins, but to no success.
if anyone knows how I should tackle this problem I would much appreciate it!
Thanks in advance.