While writing my application I came across a problem with executting SQL statement. I tried to look for a solution on the net, but none of the found helped and I still do not know how to deal with an error I get. Here is exception I get:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["FKAM8LLDERP40MVBBWCEQPU6L2S: PUBLIC.BOOK_CATEGORY FOREIGN KEY(CATEGORY_ID) REFERENCES PUBLIC.CATEGORY(ID) (2)"; SQL statement:
insert into book_category (book_id, category_id) values (?, ?) [23506-196]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
And this is how the classes looks:
Book.class
#Entity
#Table(name = "book")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String title;
private String description;
#Column(name = "release_date")
#Temporal(TemporalType.TIMESTAMP)
private Date releaseDate;
#JoinColumn(name = "cover_image")
#OneToOne(cascade = CascadeType.MERGE)
private UploadFile coverImage;
#OneToOne(cascade = CascadeType.MERGE)
private UploadFile content;
#ManyToMany
#JoinTable(name = "book_category", joinColumns = {#JoinColumn(name = "book_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "category_id", referencedColumnName = "id")})
private Set<Category> categories;
// constructors, setters, getters
}
Category.class
#Entity
#Table(name = "category")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "category_name")
private String name;
#ManyToMany(mappedBy = "categories", fetch = FetchType.LAZY)
private List<Book> books;
// ...
}
Your are missing cascade definitions there.
Your Book Category gets written before a referenced entity (book or category) gets inserted first. This is not allowed due to the constraint you specified. The solution is to define
cascade = CascadeType.ALL
On both sides of the join (both in books and in categories). This is going to ensure that JPA persists all entities in the right order.
Related
I have two classes: Category and Event. And i have a Many-To-Many relationship between then that created a table "events-categories". When i try to delete a category that is related with some event i get this error message
"could not execute statement; SQL [n/a]; constraint ["FK646NVTVT2IKHQCVFM14QKNF62: PUBLIC.EVENTS_CATEGORY FOREIGN KEY(CATEGORY_ID) REFERENCES PUBLIC.CATEGORY(ID) (CAST(2 AS BIGINT))"; SQL statement:\ndelete from category where id=? [23503-212]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"
What i want is to delete a category and no delete the events that have this category. I just want to set the deleted category in the events to null
Thats the code of the Entitys
#Data
#Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(length = 20, nullable = false)
private String name;
#ManyToMany
private Set<Event> events;
}
#Data
#Entity
public class Event {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(length = 80, nullable = false)
private String description;
#Column(nullable = true)
private LocalDate[] eventDate;
#ManyToMany
#JoinTable(name = "events_categories", joinColumns = #JoinColumn(name = "event_id"), inverseJoinColumns = #JoinColumn(name = "category_id"))
private Set<Category> categories;
}
In my project I use Spring data jpa. I have tables for many to many relationship. My entities:
#Entity
#Table(name = "SPEC")
public class SpecJpa {
#Id
private int id;
#Column(name = "NAME")
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "Creator_ID", unique = false, nullable = false, updatable = true)
private UsersJpa usersJpa;
#Column(name = "DESCRIPTION")
private String description;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name="SPEC_PARTS",
joinColumns = #JoinColumn(name="ID_PARTS", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="ID_SPEC", referencedColumnName="id")
)
private Set<PartsJpa> partsJpa;
//---------------
And Parts:
#Entity
#Table(name = "PARTS")
public class PartsJpa {
#Id
private int id;
#Column(name = "NAME")
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "ID_EXPORT", unique = false, nullable = false, updatable = true)
private ExportJpa exportJpa;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "ID_TYPE", unique = false, nullable = false, updatable = true)
private TypesJpa typesJpa;
#Column(name = "DESCRIPTION")
private String description;
#ManyToMany(fetch = FetchType.EAGER)
private Set<SpecJpa> specJpa;
Now in Controller I try to delete one row from table parts:
#PostMapping("deletePart")
public String deletePart(#RequestParam String id, Model model) {
partsService.deleteById(Integer.parseInt(id));
return "redirect:/parts";
}
But I have exception:
ferential integrity constraint violation:
"FK9Y4MKICYBLJWPENACP4298I49: PUBLIC.PARTS FOREIGN KEY(ID_EXPORT)
REFERENCES PUBLIC.EXPORT(ID) (1)"; SQL statement: /* delete
com.aleksandr0412.demo.entitiesjpa.ExportJpa / delete from EXPORT
where id=? [23503-200]], SQL: / delete
com.aleksandr0412.demo.entitiesjpa.ExportJpa */ delete from EXPORT
where id=? 2020-05-25 19:16:31.630 WARN 13387 --- [nio-8080-exec-4]
o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23503, SQLState:
23503
In my db for this entities I have 3 tables: Parts, Spec and Spec_parts. As I understand to solve this problem, I firstly should delete rows in table spec_parts, and after this I can delete row from table parts. How can I do this?
In your partsService implementation, I would recommend you first fetch the resource you are about to delete (i.e the PartsJpa) using the given id from the controller.
Next set its specJpa to null or emptySet, then call the delete method afterwards.
For this to work, ensure that method setSpecJpa(SpecJpa specJpa) and setPartJpa(PartJpa partJpa) are properly implemented.
I hope you find this helpful.
There is a unidirectional ManyToMany mapping between Role and Privilege with Role as the owning entity like so
Role
#Entity
public class Role extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "role_id")
private Integer roleId;
#Size(max = 45)
#Column(name = "role")
private String role;
#JoinTable(name = "role_privilege", joinColumns = {
#JoinColumn(name = "role_role_id", referencedColumnName = "role_id")}, inverseJoinColumns = {
#JoinColumn(name = "privilege_privilege_id", referencedColumnName = "privilege_id")})
#ManyToMany(
cascade = {
CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.REFRESH,
CascadeType.PERSIST }, fetch = FetchType.EAGER, targetEntity = Privilege.class)
private Collection<Privilege> privilegeCollection;
#Transient
private Collection<Privilege> parentPrivilegeCollection;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "roleId")
#JsonIgnore
private Collection<User> userCollection;
public Role() {
}
//getters,setter,hashcode,equals removed for brevity
}
Privilege
#Entity
public class Privilege extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "privilege_id")
private Integer privilegeId;
#Size(max = 45)
#Column(name = "name")
private String name;
#Size(max = 150)
#Column(name = "description")
private String description;
#Size(max = 45)
#Column(name = "friendly_name")
private String friendlyName;
#JoinTable(name = "privilege_hierachy", joinColumns = {
#JoinColumn(name = "parent_privilege", referencedColumnName = "privilege_id")}, inverseJoinColumns = {
#JoinColumn(name = "child_privilege", referencedColumnName = "privilege_id")})
#ManyToMany
private Collection<Privilege> privilegeCollection;
public Privilege() {
}
}
The Problem
Whenever i set updated list of privileges in a role and update, the join table is successfully updated without removing either target or owning entity, and that is desired result. The problem is on update it also affect another self join table in Privilege called privilege_hierachy which is not what is expect.
Is it possible for hibernate to only update the Role-Privilege mant-to-many relationship and let other relation unchanged.
Spring Data Jpa is used for data persistence
It sounds like you are updating the privileges by (removing old privileges and) adding new ones. If you do that, clearly, the second join table (the self-referencing table) could be updated with new rows, based on what you are passing.
I see that for the self-referencing table, Privilege, you are not setting cascade type. It defaults to no operation, and that sounds like what you want. But my guess is based on what you said "Whenever i set updated list of privileges in a role", and that tells me you are creating new privileges for a role, instead of using existing privileges and associate them with the role.
Situation: I have a masterDB and a library1DB and library2DB.
library1DB and library2DB are two separate database but has the same schema because each library must have their own database. Now we have a masterDB, this is an aggregated version of all the data in all libraries (library1DB and library2DB), still taking note of their respective ids and mapping them to their library id.
Here's I want my tables to be structured:
book
- book_id
- library_id
- title
- shelf_id
shelf
- shelf_id
- library_id
- book_id
- description
I have these models:
#Entity
public class Book {
#EmbeddedId
private BookKey bookKey;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "SHELF_ID", referencedColumnName = "SHELF_ID"),
#JoinColumn(name = "LIBRARY_ID", referencedColumnName = "LIBRARY_ID")
})
private ObjectA objectA;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({
#JoinColumn(name = "ANOTHER_ID", referencedColumnName = "ANOTHER_ID"),
#JoinColumn(name = "LIBRARY_ID", referencedColumnName = "LIBRARY_ID")
})
private ObjectB objectB;
#Column
private String title;
}
#Embeddable
public class BookKey implements Serializable {
#Column(name = "BOOK_ID")
private long bookId;
#Column(name = "LIBRARY_ID")
private long libraryId;
}
But I get this exception:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: Book column: library_id (should be mapped with insert="false" update="false")
I've tried using #IdClass instead of #Embeddable and #EmbeddedId, and I got this:
Caused by: org.hibernate.DuplicateMappingException: Table [book] contains physical column name [libraryId] represented by different logical column names: [libraryId], [LIBRARY_ID]
Any help?
Thanks!
You should add insert="false", update="false" for the second mapped column library_id.
Try this:
#JoinColumn(name = "LIBRARY_ID", referencedColumnName = "LIBRARY_ID",
insertable = false, updatable = false)
I was getting the same problem. If you add insert="false", update="false" only to one, you will get an exception stating that you mixed writable and non-writables and that this is not allowed. The following works:
I solved it using the #PrimaryKeyJoinColumns, try this (from another example):
#ManyToOne
#PrimaryKeyJoinColumns(value = {
#PrimaryKeyJoinColumn(name = "country_code", referencedColumnName = "country_code"),
#PrimaryKeyJoinColumn(name = "zip_code", referencedColumnName = "code")
})
private Zip zip;
#ManyToOne
#PrimaryKeyJoinColumns(value = {
#PrimaryKeyJoinColumn(name = "country_code", referencedColumnName = "country_code"),
#PrimaryKeyJoinColumn(name = "state_code", referencedColumnName = "state_code"),
#PrimaryKeyJoinColumn(name = "city_name", referencedColumnName = "name")
})
private City city;
from Hibernate throws AnnotationException on column used by multiple overlapping foreign keys
I have three entities. The first one is Company entity (see below).
#Entity
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String name;
#JoinColumn(name = "company_id")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Employee> employees;
#OneToMany(mappedBy = "company")
private List<HistoryRecord> historyRecords;
The second is Employee
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Integer id;
#Column
String name;
#ManyToOne
#JoinColumn(name = "company_id", nullable = true)
private Company company;
#OneToMany(mappedBy = "employee")
private List<HistoryRecord> historyRecords;
Here is my HistoryRecord class
#Entity
public class HistoryRecord {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Integer id;
#ManyToOne
#JoinColumn(name = "company_id")
Employee employee;
#ManyToOne
#JoinColumn(name = "employee_id")
Company company;
#Column(name = "hire_date")
Date hireDate;
#Column(name = "resign_date")
Date resignDate;
When I'm trying to execute delete operation on Employee I'm getting this error
HTTP Status 500 - Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [delete from employee where id=?]; constraint ["CONSTRAINT_12: PUBLIC.HISTORY_RECORD FOREIGN KEY(EMPLOYEE_ID) REFERENCES PUBLIC.EMPLOYEE(ID)
I think the problem is in cascade operation but I'm not sure. Is anybody can say how can I fix it?
The problem is due to the relationship of Employee -- HistoryRecord. The employee property on HistoryRecord is not nullable. If you want the HistoryRecord to be deleted when an employee is being deleted you need to add the cascade attribute to the #OneToMany(mappedBy = "employee") for historyRecords on Employee.
#OneToMany(mappedBy = "employee",cascade = CascadeType.REMOVE)
The ENDDM generates
ALTER TABLE "public"."project_group" ADD CONSTRAINT "mandant" FOREIGN KEY (mandant_id) REFERENCES "mandant" ("mandant_id") ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED;
for the database and
#OneToMany(cascade = CascadeType.REMOVE)
in Java.
Update your relation mapping in Company class is is missing cascade.
#OneToMany(mappedBy = "company", cascade = CascadeType.ALL)
private List<HistoryRecord> historyRecords;