JPA OneToOne association without foreign key not working - java

I am using Hibernate/JPA, and have 3 tables:
Contact
pk contact_id
fk member_id
Employee
pk employee_id
fk member_id
Members
pk member_id
I have:
#Entity(name = "Contact" )
public class Contact implements Serializable {
#Id
#SequenceGenerator(allocationSize = 1, name = "contact_sequence", sequenceName = "contact_ids")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "contact_sequence")
private java.lang.Long contact_id;
#OneToOne(cascade = CascadeType.ALL, targetEntity = Members.class)
#JoinColumn(name = "member_id")
private Members member;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "member", referencedColumnName = "member")
private Employee employee;
and
#Entity(name = "Employee")
public class Employee implements Serializable {
#Id
#SequenceGenerator(allocationSize = 1, name = "employee_sequence", sequenceName = "employee_ids")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "employee_sequence")
private java.lang.Long employee_id;
and
#Entity(name = "Members")
#Table(name = "Members")
public class Members implements Serializable {
#Id
#SequenceGenerator(allocationSize = 1, name = "members_sequence", sequenceName = "member_ids")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "members_sequence")
private java.lang.Long member_id;
My problem is with the Contact entity private Employee employee;. When I start my Jboss server:
StartException in service jboss.persistenceunit.
Question
How do I annotate the private Employee employee; on the Contact entity?
Thank you

You are almost properly defining the private Members member;, so is there a reason for not doing the same for private Employee employee; ?
Like :
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employee", referencedColumnName = "employee_id")
private Employee employee;
Also a simple link, just to cross-check the overall #JoinColumn functionality
===EDIT===
As it looks there is indeed a data structure issue as from the first place the relation is ManyToOne,
If you could try the below example :
//Employee
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "contact_id", referencedColumnName = "contact_id")
private Contact contact;
//Contact
#OneToMany(fetch = FetchType.LAZY, mappedBy = "employee_id")
private List<Employee> employees = new ArrayList<>();
Then by selecting the contact.getEmployees() should do the trick

Related

Exclude table using CrudRepository in Java

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

Hibernate MappedBy for Multiple columns

I am using Postgresql for my database and it contains a table called user and a table called friendship, which has 2 foreign keys userA_id and userB_id. I know how to use mappedBy to check for friendships based on userA_id but I am not sure how to check for userB_id. Is there a way to tell hibernate to check a user ID from user table with both of columns on friendship table?
EDIT: Here is the code I currently have.
#Entity
#Table(name = "users")
public class UserDB implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "userid", nullable=false)
public int userID; //not null
#OneToMany (targetEntity = FriendshipDB.class, mappedBy = "userA_ID", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
//#OneToMany (targetEntity = FriendshipDB.class, mappedBy = "userB_ID", cascade = CascadeType.ALL, fetch=FetchType.EAGER)
public List<FriendshipDB> friends = new ArrayList<>();
}
#Entity
#Table(name = "friendships")
public class FriendshipDB implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "friendshipid", nullable = false)
private int friendshipID; //not null
#ManyToOne
#JoinColumn(name="usera_id")
private UserDB userA_ID; //not null
#ManyToOne
#JoinColumn(name = "userB_id")
private UserDB userB_ID;
}
I think this is very specific mapping but the only solution I know is to go with 2 association like this:
#OneToMany(mappedBy = "user1")
private Collection<User> usersByFirst;
#OneToMany(mappedBy = "user2")
private Collection<User> usersBySecond;

Hibernate - Populate sub entity on insert

Ive added 2 hibernate model objects
First table
#Entity
#Table(name = "ACTIVITIES")
public class ActivityMO extends ModelBase {
#Column(name = "CA_ID", nullable = false, insertable = true,updatable = true, length = 22, precision = 0)
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "G1")
#SequenceGenerator(name = "G1", sequenceName = "CSM_ACTIVITIES_SEQ")
private Long id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "activityId", cascade = {CascadeType.ALL})
#Fetch(FetchMode.JOIN)
List<ActivitiesProductsMO> relatedProducts;
...getters / setters
}
The other table is
#Entity
#Table(name = "ACTIVITIES_PRODUCTS")
public class ActivitiesProductsMO {
#Column(name = "CAP_ID")
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "G1")
#SequenceGenerator(name = "G1", sequenceName = "ACTIVITIES_PRODUCTS_SEQ")
private Long id;
#Column(name = "CAP_ACTIVITY_ID")
private Long activityId;
#Column(name = "CAP_PRODUCT_ID")
private Long productId;
...getters/setters
}
The point is to populate each db record for ActivitiesProductsMO.activityId with ActivityMO.id value
I.e.
If I create an activity record with id = 555
I'll get another activity_product record with activityId of 555
How can i get this to work?
Thank you!
Instead of manually trying to map the entitiy relations with long values you should use a bidirectional OneToMany relationship from ActivityMO to ActivitiesProductsMO
change ActivitiesProductsMO to:
#Entity
#Table(name = "ACTIVITIES_PRODUCTS")
public class ActivitiesProductsMO {
// cut unimportant code ...
#ManyToOne
#JoinColumn(name = "CAP_ACTIVITY_ID")
private ActivityMO activityId;
// cut unimportant code ...
}
If you then were to persist an ActivityMO that already has ActivitiesProductsMO entries in its relatedProducts List, the Cascade type should actually take care and create those products while filling out the CAP_ACTIVITY_ID database field with the right value.
Another Possible Solution:
Use a Unidirectional OneToMany:
#Entity
#Table(name = "ACTIVITIES")
public class ActivityMO extends ModelBase {
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
#Fetch(FetchMode.JOIN)
#JoinColumn(name = "CAP_ACTIVITY_ID")
List<ActivitiesProductsMO> relatedProducts;
}
And remove the
private Long activityId;
from your ActivitiesProductsMO class.
This should both lead to identical database structure. But in the second case you would no longer have the "backlink" inside java from ActivitiesProductsMO to ActivityMO

JPA, inheritance JOINED, multiple ID's

I have a little JPA question.
Assume you have such tables: (structure is fixed)
PERSON
--
ID,
DEPARTMENT_ID
...
SPECIALWORKER
------
ID, PERSON_ID, SPECIALDEPARTMENT_ID
...
DEPARTMENT
-------
ID,
...
SPECIALDEPARTMENT
-------
ID,
...
In Java I would build it with a simple hierarchy: SpecialWorker extends Person and SpecialDepartment extends Department. We will have "simple" Persons as well as "simple" Departments.
In JPA I try to build that scenario with a JOINED_Table inheritance, but I can't get it working. Any ideas?
edit
the coding, i hope i missed nothing.
I got a integrity exception when i try to insert a specialworker.
When i insert a specialworker jpa has to set the fk to departement (baseclass person) as well as the fk to the special departement (from the concrete current class)
#Entity
#Table(name = "DEPARTEMENT")
#Access(AccessType.FIELD)
#Inheritance(strategy = InheritanceType.JOINED)
public class Departement
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Integer id;
...
}
#Entity
#Table(name = "SPECIALDEPARTEMENT")
#Access(AccessType.FIELD)
#PrimaryKeyJoinColumn(name = "ID_DEPARTEMENT", referencedColumnName = "ID")
public class SpecialDepartement
extends Departement
implements Serializable
{
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", updatable = false, insertable = false)
private Integer id01;
#OneToMany(mappedBy = "specialDepartement", cascade = CascadeType.ALL, orphanRemoval = true)
private List<SpecialWorker> workers;
...
}
#Entity
#Table(name = "PERSON")
#Access(AccessType.FIELD)
#Inheritance(strategy = InheritanceType.JOINED)
public class Person
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
#Max(19)
private Long id;
#ManyToOne
#JoinColumn(name = "ID_DEPARTEMENT", referencedColumnName = "ID", nullable = false)
private Departement departement;
...
}
#Entity
#Table(name = "SWORKER")
#Access(AccessType.FIELD)
#PrimaryKeyJoinColumn(name = "ID_PERSON", referencedColumnName = "ID")
public class SpecialWorker
extends Person
{
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", updatable = false, insertable = false)
private Integer id01;
#ManyToOne
#JoinColumn(name = "ID_SPECIALDEPARTEMENT", referencedColumnName = "ID", nullable = false)
private SpecialDepartement specialdepartement;

Hibernate many to many mapping

I have an existing database modeled the following way:
Student - SchoolId(PK), StudentId(PK), StudentName
Teacher - SchoolId(PK), TeacherId(PK), TeacherName
Student_Teacher - SchoolId(PK), StudentId(PK), TeacherId(PK)
Foreign key references exist from Student_Teacher to respective entities.
Now I am creating hibernate entities for this existing database. And I am running into weird issues creating Many-to-Many mapping from Student to Teacher.
#Entity
#Table(name = "Student")
public class Student {
#EmbeddableId
private StudentPK itemId;
#Column(name="StudentName")
private String studentName;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name="Student_Teacher", joinColumns={#JoinColumn(name="SchoolId", referencedColumnName="SchoolId"),#JoinColumn(name="StudentId", referencedColumnName="StudentId")}, inverseJoinColumns={#JoinColumn(name="SchoolId", referencedColumnName="SchoolId"),#JoinColumn(name="TeacherId", referencedColumnName="TeacherId")})
private List<Teacher> attachments=new ArrayList<Teacher>();
}
The above code compains about some duplicate SchoolId reference.
Any ideas?
As I see that there is an issue in your mapping of entities, It should be as follows
school - school_id(PK), school_name
student - student_id(PK) , student_name, fk_school_id(FK),
teacher - teacher_id(PK), teacher_name , fk_school_id(FK)
*student_teacher* - student_teacher_id(PK), fk_student_id(FK), fk_teacher_id(FK)
and Entity clasess as follows
School Entity
#Entity
#Table(name = "school")
public class School {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column (name = "school_id")
private int Id;
#Column(name="school_name")
private String schoolName;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "school")
private Set<Student> students = new HashSet<Student>
#OneToMany(fetch = FetchType.LAZY, mappedBy = "school")
private Set<Teacher> teachers = new HashSet<Teacher>
}
Student Entity
#Entity
#Table(name = "student")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column (name = "student_id")
private int Id;
#Column(name="student_name")
private String studentName;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "school_id", nullable = false)
private School school;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "student_teacher", joinColumns = {#JoinColumn(name = "fk_student_id") }, inverseJoinColumns = { #JoinColumn(name = "fk_teacher_id") })
private List<Teacher> teachers = new ArrayList<Teacher>();
}
Teacher Entity
#Entity
#Table(name = "teacher")
public class Teacher {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column (name = "teacher_id")
private int Id;
#Column(name="teacher_name")
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "school_id", nullable = false)
private School school;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "student_teacher", joinColumns = {#JoinColumn(name = "fk_teacher_id") }, inverseJoinColumns = { #JoinColumn(name = "fk_student_id") })
private List<Student> students =new ArrayList<Student>();
}
hope this will solve this problem..
as you have declare 'SchoolId' as PK in Student_Teacher table it will not allow you to add duplicate entry for SchoolId field for Student_Teacher table and this is not the case. thus the above relationship will gives duplicate SchoolId reference. when you are going to add two different students from same school into Student_Teacher table..
Did you define the various PKs per entity as compound keys, as i note that you use multiple PKs per entity. Is there any constraint why you can't use a sole PK per entity and just use a relation table to bind the 2 entities?

Categories