Spring JPA Postgresql - Composite keys are duplicated when one is not - postgresql

I am having some troubles and hope you can help me, I have the following entity:
App class:
#Entity
#Table(name = "apps")
public class App {
#Id
#Column(length = 15)
private String name;
#Column(length = 40)
private String web;
#Column(length = 50)
private String mailDomain;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "app")
private List<SocialNetwork> socialNetworks = new ArrayList<>();
//getters, setters, equals and hash
Social Network Class:
#Entity
#Table(name = "social_networks")
#IdClass(SocialNetworkCompositeKey.class)
public class SocialNetwork {
#Id
#Column(length = 15)
private String name;
#Id
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "app")
private App app;
#Column(nullable = false, length = 40)
private String url;
//getters, setters, equals and hash
SocialNetworkCompositeKey Class:
public class SocialNetworkCompositeKey implements Serializable {
private String name;
private String app;
//equals and hash
Now whenever I try to insert an App either in my Program or directly in the DB, I get the Exception:
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "uk_590itpuvpqppd9f0g2w5y8bml"
Detail: Key (app)=(Uli App) already exists.
This while trying to insert 2 records with:
app name url
----+---------+-----------+---------
1 | Uli App | Twitter | http...
----+---------+-----------+---------
2 | Uli App | Linkedin | http...
----+---------+-----------+---------
I am using the latest version of both Spring boot and JPA. So I use JpaRepository for my repositories. Even if I try to enter those rows manually in the DB with pgAdmin it'll give me the same error.
I am not sure if it's related but I use ddl-auto: update from hibernate to auto create the tables.
I hope you guys can help me, cheers.

as #Morteza said my relationships were wrong. With this and other tutorial I found after digging alot (I really Googled alot before posting this) I was able to fix it by changing the relationship from #OneToMany to #ManyToOne in the Social Networks class. These are changes I've made:
App class:
#OneToMany(mappedBy = "app", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<SocialNetwork> socialNetworks = new ArrayList<>();
Social Network class:
#Id
#ManyToOne(fetch = FetchType.LAZY)
private App app;
Thanks for the help guys!

Related

Spring Data Jpa OneToMany save bidirectional

I have a problem with saving child entities.
Here is my example. My model classes look like this:
#Entity
public class ImportDocument {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;
private boolean imported;
#Transient
private Status status;
#Basic
private char statusValue;
#OneToMany(mappedBy = "importDocument" , cascade = {CascadeType.ALL})
private List<ImportDocumentItem> importDocumentItems;
}
#Entity
public class ImportDocumentItem {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "import_document_id")
#JsonIgnore
private ImportDocument importDocument;
}
I have implemented JpaRepository interfaces for both domain classes.
I try to save with:
importDocumentRepository.save(importDocument);
When I save ImportDocument object, everything is inserted. But the problem is that, the import_document_item.import_document_id (which is foreign key of import_document_id) attribute is filled with null value, not with id of import_document that I expected. How can I fix this issue?
Thanks a lot.
You have to set entity relations on both side before saving. Here an example
ImportDocument importDocument = new ImportDocument();
//...
importDocument.setImportDocumentItems(items);
items.forEach(ImportDocumentItem::setImportDocument);
importDocumentRepository.save(importDocument);

Why my foreign key is null when saving to h2 db, using JPA

What is the difference between these 2 codes. The 1st one shows null on my foreign key which is individualId. The 2nd one is not. Why?
//1st code:
#Entity
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Individual {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "INDIVIDUAL_ID")
private Long individualId;
#OneToMany(mappedBy="individual",cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Identification> identifications = new ArrayList<Identification>();
}
#Entity
public class Identification {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "IDT_ID")
private Long id;
#ManyToOne
#JoinColumn(name="individualId")
private Individual individual;
//second code
//replaced #OneToMany in the first code & then i just dont add #ManyToOne in the Identification Class and it works fine. Why?
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "INDIVIDUAL_ID", referencedColumnName = "INDIVIDUAL_ID")
private List<Identification> identifications = new ArrayList<Identification>();
When i search for JPA tutorial in google the 1st code is the one that i always read. declare #OneToMany in the parent class and add mappedBy, declare #ManyToOne in the child class. But why the 2nd code works perfect than the 1st code? it just let me declare #OneToMany only in the parent class ?
In the class Identification the name of the #JoinColumn does not match any column in your class Individual. It must be the name of the column in the database, which is INDIVIDUAL_ID:
#JoinColumn(name="INDIVIDUAL_ID")

Moving #OneToMany from Entity to Embeddable

It's my first post, so I hope I do it the right way. I have searched two days for an equivalent Problem, but did not find anything.
Here is what I did:
We have an Entity, that contains (beside others) the folowing fields:
#Entity
#Access(AccessType.FIELD)
#Table(name = "component")
public class Component {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
.
.
#OneToMany
#JoinTable(name = "component_dokumentation",
joinColumns = #JoinColumn( name = "component_id" ),
inverseJoinColumns = #JoinColumn(name = "dokumentation_id"))
private Set<FileType> dokumentation;
private Long keySisMf = 0L;
.
.
// Getter and Setter and stuff
}
After one year of usage we have found out, that our Entity became too big and that we have to use DTO Objects to transfer data to the Client, modify them and return them to the Server. For this purpose we modelled an embeddable Entity ComponentAttributes.
So right now it Looks like:
#Entity
#Access(AccessType.FIELD)
#Table(name = "component")
public class Component {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
.
.
#Embedded
private ComponentAttributes componentAttributes;
.
.
}
#Embeddable
#Access(AccessType.FIELD)
public class ComponentAttributes {
private static final long serialVersionUID = 1L;
#OneToMany
#JoinTable(name = "component_dokumentation",
joinColumns = #JoinColumn( name = "component_id" ),
inverseJoinColumns = #JoinColumn(name = "dokumentation_id"))
private Set<FileType> dokumentation;
private Long keySisMf = 0L;
.
.
// Getter and Setter and stuff
}
We did not change anything in the Database. We have encountered Problems in setting values for the set documentation. The field keySisMf is not a Problem. The Problems are just related to the documentation (I must add that FileType is just a Basic Entity consisting of an id and several Strings, so nothing Special). Getting the values and transfering them to the Client is fast and correct. Telling the Server to Change keySisMf is not a Problem. Telling the Server to add or remove a FileType instance simply does not work. No Errors but no changes.
We have logged the JPA generated SQL and there is no SQL generated for component.getComponentAttributes().setDokumentation(fileSet).
We use a Glassfish 4.1.1 Server with an ORACLE Database. Did I miss something when moving dokumentation from Component to ComponentAttributes????
Thanks for your help and patience.
Chris

ERROR: update or delete on table "tablename" violates foreign key constraint

I'm trying to delete the parent student or parent course and I get this error:
Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on table "student" violates foreign key constraint "fkeyvuofq5vwdylcf78jar3mxol" on table "registration"
RegistrationId class is a composite key used in Registration class. I'm using Spring data jpa and spring boot.
What am I doing wrong? I know that putting cascadetype.all should also remove the children when the parent is deleted but it is giving me an error instead.
#Embeddable
public class RegistrationId implements Serializable {
#JsonIgnoreProperties("notifications")
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "student_pcn", referencedColumnName="pcn")
private Student student;
#JsonIgnoreProperties({"teachers", "states", "reviews"})
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "course_code", referencedColumnName="code")
private Course course;
Registration class
#Entity(name = "Registration")
#Table(name = "registration")
public class Registration {
#EmbeddedId
private RegistrationId id;
When you're using a relational DB, you are setting entities with relationships between these entities.
The error that you're getting means that:
You're trying to delete a record that its primary key is functioning as a foreign key in another table, thus you can't delete it.
In order to delete that record, first, delete the record with the foreign key, and then delete the original that you wanted to delete.
I made it work by using hibernate #OnDelete annotation. Some how the JPA.persistence CascadeTypes were not working. They had no effect for whichever I chose.
Just like below. Now I can remove the parent Student or the parent Course and all children(Registrations) are deleted with them.
#Embeddable
public class RegistrationId implements Serializable {
#JsonIgnoreProperties("notifications")
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne
#JoinColumn(name = "student_pcn", referencedColumnName="pcn")
private Student student;
#JsonIgnoreProperties({"teachers", "states", "reviews"})
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne
#JoinColumn(name = "course_code", referencedColumnName="code")
private Course course;
Foreign keys guarantee that an entry will exist in another table. This is a way of ensuring data integrity. SQL will never allow you to delete this entry while it still deletes in the other table. Either (1) this is letting you know you would have made a grave mistake by deleting this thing which is required or (2) you would like to put in a cascading delete so that not only is this entry deleted but so is what is supposed to be referencing it in the other table. Information on cascading deletes can be found here and written fairly easily (https://www.techonthenet.com/sql_server/foreign_keys/foreign_delete.php). If neither of these two descriptions fits you, evaluate why your foreign key relationship exists in the first place because it probably should not.
Try this method too. I got the answer with this method,This is just a test to remove.
Pay attention to the cascade!
MyUser Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstname;
private String lastname;
private String mobile;
#Column(unique = true)
private String email;
private Long date;
private LocalTime localiime;
private LocalTime localiimeend;
#ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.MERGE)
#JoinColumn(foreignKey = #ForeignKey(name = "role_fk"))
private Role role;
Role Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
#OneToMany(mappedBy = "role", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<MyUser> users;
#ManyToOne (fetch = FetchType.LAZY,cascade = CascadeType.MERGE)
#JoinColumn(foreignKey = #ForeignKey(name = "rolecat_fk"))
private rolecat rolecat;
rolecat Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToMany(mappedBy = "rolecat", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Role> roles;

How to show 2 different type of mappings between 2 entity classes, holding each other's reference

The mappings between the 2 tables(Department and Employee) is as follows (Link for the image showing mapping is also provided):
Every department has one and only one department head.
Every department can have more than one employee.
dept_id and empId are primary keys of their respective tables.
dept_head(It is the Employee Id) and dept are foreign keys of their
respective tables.
Mapping Employee and Department table
I created entity classes for the above 2 tables (The structure is provided below).
Employee Class:
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "empId")
private Integer empId;
#Size(max = 45)
#Column(name = "name")
private String name;
#Size(max = 45)
#Column(name = "address")
private String address;
#Size(max = 45)
#Column(name = "grade")
private String grade;
#Size(max = 45)
#Column(name = "email")
private String email;
#JoinColumn(name = "dept", referencedColumnName = "dept_id")
#ManyToOne
private Department deptartment;
.. ...
}
Department class:
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 8)
#Column(name = "dept_id")
private String deptId;
#Size(max = 45)
#Column(name = "name")
private String name;
#JoinColumn(name = "dept_head", referencedColumnName = "empId")
#OneToOne
private Employee deptHead;
#OneToMany(mappedBy = "deptartment")
private List<Employee> employeeList;
....
...
}
If I am adding mappedBy in Employee Class (like I did in Department), to show OneToOne mapping between empId and deptHead,the code is compiling and running. However, If I do not add the mappedBy statement in Employee class, as the above code shows, the code still compiles and runs fine.
I would want to know why the code above works even if I am not providing mappedBy in employee class.
If anybody can help me clearing the above doubts and explaining the logic behind its working would be great as I am new to this.
It is not quite clear where you tried to user it with and without the mappedBy attribute.
But if I get your question correctly, you ask why you can have only one or both sides annotated?
It depends on which side is the source and destination of your relation or wheter it's bi-directional. On the Java-side you can have a relation always in both directions due to object references, but on the Database-side, you might only have it in one direction.
Check out JPA Wiki book on that topic for more details.
Additionally, the API doc for OneToOne states:
Specifies a single-valued association to another entity that has
one-to-one multiplicity. It is not normally necessary to specify the
associated target entity explicitly since it can usually be inferred
from the type of the object being referenced. If the relationship is
bidirectional, the non-owning side must use the mappedBy element of
the OneToOne annotation to specify the relationship field or property
of the owning side.