I am creating a database of items and have been trying to assign multiple database entities to a single item however I am struggling to get past an error I keep having. I am unsure what I am doing wrong can someone help?
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Referential integrity constraint violation: "FKKPIB0GWXM6UFS3SJJ2NCI64AR: PUBLIC.FEATURES FOREIGN KEY(ITEM_ID) REFERENCES PUBLIC.ITEM(ITEM_ID) (CAST(1020 AS BIGINT))"; SQL statement: INSERT INTO FEATURES(FEATURE_ID, ITEM_ID) VALUES(101, 1020), (102,1021), (103,1021), (104,1021)
Item.java
#Entity
#Table(name="item")
public class Item {
#Id
#Column(name = "item_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#Enumerated(EnumType.STRING)
private ItemType itemtype;
private int weight;
private int recovers;
private int priority;
private String desc;
#OneToMany(mappedBy = "item")
private List<Feature> features;
}
Feature.java
#Entity
#Table(name = "features")
public class Feature {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long feature_id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "item_id", insertable = false, updatable = false)
#JsonIgnore
private Item item;
}
data.sql
INSERT INTO SPELLS(SPELL_ID, ITEM_ID)
VALUES(101, 1020),
(102, 1021),
(103, 1021),
(104, 1021)
;
INSERT INTO ITEM(ITEM_ID, NAME, ITEMTYPE, WEIGHT, RECOVERS, PRIORITY, DESC)
VALUES (1010,'Hunting Knife','DAGGER',1,5,3,''),
(1011,'Relic Sword','SWORD',3,10,3,''),
(1012,'Relic Spear','SPEAR',3,8,3, ''),
(1013,'Relic Axe','AXE',4,12,3, ''),
(1014,'Old Club','MACE',4,10,3,''),
(1015,'Crooked Stick','STAFF',2,3,3,''),
(1016,'Training Bow','BOW',2,20,4,''),
(1017,'Training Crossbow','CROSSBOW',2,20,4,''),
(1018,'Grass Sling','SLING',2,20,4,''),
(1019,'Wooden Shield','SHIELD',4,20,4,''),
(1020,'Poison wand','WAND', 1,0,4,''),
(1021,'Mushroom staff','STAFF',2,3,3,'')
;
Related
I have the following table structure.
(The unique constraint is to avoid multiple 'details' to the same employee - I can't change the db structure).
https://i.ibb.co/r3pYQFj/fk.png
create table employee (
employee_id number(19),
salary number(10),
constraint pk_employee primary key (employee_id)
);
create table employee_details (
employee_details_id number(19),
employee_id number(19) not null,
address varchar2(256),
gender char(1),
constraint fk_employee foreign key (employee_id) references employee (employee_id),
constraint fk_employee_unq unique (employee_id)
);
Model class:
#Entity
#Table(name = "EMPLOYEE")
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "empgen")
#SequenceGenerator(name = "empgen", sequenceName = "SEQ_EMP", allocationSize = 1)
#Column(name = "EMPLOYEE_ID")
private Long id;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="EMPLOYEE_ID")
private EmployeeDetail empDetail;
...
#Entity
#Table(name = "EMPLOYEE_DETAIL")
public class EmployeeDetail implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "empdetgen")
#SequenceGenerator(name = "empdetgen", sequenceName = "SEQ_EMP_DET", allocationSize = 1)
#Column(name = "EMPLOYEE_DETAILS_ID")
private Long id;
#Column(name = "EMPLOYEE_ID")
private Long employeeId;
...
I have a rest controller that receive a JSON like this:
{
"employee": {
"salary": 80000,
"empDetail": {
"adress": "ST EXAMPLE",
"gender": "M"
}
}
}
I'm trying to persist all the entities via hibernate (5.4.28) saving Employee as the first entity, then with its primary key, EmployeeDetails using it's parent primary key but I get this:
java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("DCC"."EMPLOYEE_DETAILS"."EMPLOYEE_ID")
Why it's trying to save the child before the parent?
How the the class should be mapped?
I guess it's because Hibernate thinks that by putting #JoinColumn on Employee.empDetail, EMPLOYEE_ID belongs to the employee_details table.
Try putting creating a property EmployeeDetail.employee and put #JoinColumn on that one. If you need a reference from Employee, use #OneToOne(mappedBy=...).
How to use #JoinColumn
Activate logging to see which statements are executed
I will try to explain my issue:
I am using Spring Boot/Hibernate and the parent entity is
getters/setters and other fields are omitted
public class BaseEntity {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Valid
#JsonManagedReference
#OneToMany(mappedBy = "contract", fetch = FetchType.EAGER, orphanRemoval = true, cascade = {CascadeType.MERGE, CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REMOVE})
#OnDelete(action = OnDeleteAction.CASCADE)
private List<ChildEntity> myList = new ArrayList<>();
public void addChildEntityChildEntity list) {
myList.add(list);
list.setChildEntity(this);
}
public void removeChildEntity(ChildEntity entity) {
myList.entity(entity);
list.setChildEntity(null);
}
public List<ChildEntity> getChildEntitys(){
return this.myList;
}
public class ChildEntity {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Valid
#JsonBackReference
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "baseentity_id", referencedColumnName = "id",nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
private BaseEntity baseEntity;
//here is the self reference in the child
#Nullable
#Valid
#ManyToOne(fetch = FetchType.EAGER, cascade={CascadeType.REMOVE, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinColumn(name = "reference_child_id", referencedColumnName = "id")
#OnDelete(action = OnDeleteAction.CASCADE)
private ChildEntity referenceChildEntity;
public void addChildEntity(ChildEntity childEntity) {
this.referenceChildEntity = childEntity;
referenceChildEntity.setChildEntity(this);
}
public void removeChildEntity() {
referenceChildEntity.setChildEntity(null);
referenceChildEntity = null;
}
public void addToParentEntity(BaseEntity baseEntity) {
baseEntity.addChildEntity(this);
this.setChildEntity(baseEntity);
}
public void removeBaseEntity() {
this.baseEntity.removeChildEntity(this);
this.baseEntity = null;
}
These are the entities that are important:
However when I try to delete the the BaseEntity: AND there is a relationship with ChildEntity that has other ChildEntity relationships I get a constraint error
Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on table "base_entity" violates foreign key constraint "reference_child_id" on table "base_entity"
Detail: Key (id)=() is still referenced from table "base_entity".
Where: SQL statement "delete from base_entity where id = id.id"
this is the constraint from the psql:
CONSTRAINT_id_fkey FOREIGN KEY (reference_child_id)
REFERENCES base_entity (id) MATCH SIMPLE
Finally, the delete happens in sql function that looks like:
create or replace function delete_base_entity_by_id(
base_id int
)
returns void as
$BODY$
declare
loop_base base_entity;
loop_child child_entity;
begin
for loop_base in (select * from base_entity where original_id = (select original_id from base_entity where id = base_id) order by start_date, id desc) loop
for loop_child in (select * from child_entity where base_id = loop_base.id order by id desc) loop
delete from child2 where child_id = loop_child.id;
delete from child3 where child_id = loop_child.id;
delete from child4 where child_id = loop_child.id;
delete from child5 where loan_child_id = loop_child.id;
delete from child6 where loan_child_id = loop_child.id;
delete from child7 where child_id = loop_child.id;
delete from child8 where child_id = loop_child.id;
delete from child9 where id = loop_child.id;
end loop;
delete from base_entity where id = loop_base.id;
end loop;
delete from child_entity where id = loop_base.loan_id;
end
$BODY$
language plpgsql;
I have tried to add on delete cascade on the tables but there is problem with the children that i try to delete with the sql function
alter table child_entity
drop constraint id_fkey,
add constraint id_fkey
foreign key (reference_child_id)
REFERENCES child_entity (id)
on delete cascade;
Any ideas and suggestions on this really apriciated:
To fix this, you can use a deferred foreign key constraint.
alter table child_entity
drop constraint id_fkey,
add constraint id_fkey
foreign key (reference_child_id)
REFERENCES child_entity (id)
deferrable initially deferred;
This will cause the database to enforce constraints at transaction commit rather than after the statement.
I want to map an entity, which has a relationship with another table, but when mapping that relationship, it doesn't find the "Cardinality" column.
This is the code:
Entity elemento:
#Entity
#Table(name = "elemento")
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="clave", discriminatorType = DiscriminatorType.STRING, length=10)
public class Elemento implements Serializable, GenericInterface {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "clave", insertable = false)
private String clave;
#Column(name = "numero")
private String numero;
#Column(name = "nombre")
private String nombre;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Proyectoid")
private Proyecto proyecto;
#Column(name = "descripcion")
private String descripcion;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "EstadoElementoid", referencedColumnName="id")
private EstadoElemento estadoElemento;
Entity actor:
#Entity
#Table(name = "actor")
#Inheritance(strategy=InheritanceType.JOINED)
#PrimaryKeyJoinColumn(name = "Elementoid", referencedColumnName = "id")
#DiscriminatorValue("ACT")
public class Actor extends Elemento implements Serializable, GenericInterface, ElementoInterface {
private static final long serialVersionUID = 1L;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "Cardinalidadid", referencedColumnName = "id")
private Cardinalidad cardinalidad;
This is the description of the tables:
TABLE ACTOR:
| actor | CREATE TABLE `actor` (
`otraCardinalidad` varchar(45) DEFAULT NULL,
`Elementoid` int(11) NOT NULL,
`Cardinalidadid` int(11) NOT NULL,
PRIMARY KEY (`Elementoid`),
KEY `FKActor872913` (`Cardinalidadid`),
KEY `FKActor148309` (`Elementoid`),
CONSTRAINT `FKActor148309` FOREIGN KEY (`Elementoid`) REFERENCES
`elemento` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `FKActor872913` FOREIGN KEY (`Cardinalidadid`) REFERENCES
`cardinalidad` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
TABLE CARDINALIDAD
| cardinalidad | CREATE TABLE `cardinalidad` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`nombre` varchar(10) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uniqueCardinalidad` (`nombre`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 |
This error appears
02:57:43.663 [qtp1469821799-35] DEBUG
com.mchange.v2.c3p0.impl.NewPooledConnection -
com.mchange.v2.c3p0.impl.NewPooledConnection#48c2c8ce handling a
throwable. java.sql.SQLException: Column 'cardinalidadid' not found.
I have relation as shown bellow:
#Entity
#Table(name = "ORDER_", catalog = "smartorder")
public class Order implements Serializable {
/**
* serial version id
*/
private static final long serialVersionUID = 13875615L;
#Id
#Column(name = "ORDER_ID", unique = true, nullable = false)
#SequenceGenerator(name = "ORDER_ID_GEN", sequenceName = "ORDER_ID_SEQ")
#GeneratedValue(generator = "ORDER_ID_GEN")
private long orderId;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "INVOICE_ID", referencedColumnName = "INVOICE_ID")
private Invoice invoice;
// setters and getters
}
#Entity
#Table(name = "INVOICE_")
public class Invoice implements Serializable {
/**
* serial version id
*/
private static final long serialVersionUID = 13875612L;
#Id
#Column(name = "INVOICE_ID", unique = true, nullable = false)
#SequenceGenerator(name = "INVOICE_ID_GEN", sequenceName = "INVOICE_ID_SEQ")
#GeneratedValue(generator = "INVOICE_ID_GEN")
private int invoiceId;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "ORDER_ID", referencedColumnName = "ORDER_ID")
private Order order;
#Column(name = "SUB_TOTAL", precision = 6, nullable = false)
private double subTotal;
#Column(name = "SERVICE_TAX", precision = 6, nullable = false)
private double serviceTax;
#Column(name = "VAT", precision = 6, nullable = false)
private double vat;
#Column(name = "SURCHAARGE", precision = 6, nullable = false)
private double surChaarge;
#Column(name = "GRAND_TOTAL", precision = 6, nullable = false)
private double grandTotal;
//setters and getters
}
I am able to save the records properly. But when i am trying to update orders objects by setting invoice object to order object then the order object is nor persisting only invoice object is persisting.
Order o = getSession().load(Order.class,1L);
o.setInvoice(new Invoice(.........));
getSession().update(o);
in console I am able to see one SQL statement only,
insert into INVOICE_ (DISCOUNT, GRAND_TOTAL, ORDER_ID, ROUNDING, SERVICE_TAX, SUB_TOTAL, SURCHAARGE, VAT) values (?, ?, ?, ?, ?, ?, ?, ?)
Invoice Id is not getting update in Order table :(
Can anyone suggest whats the issue is.
Thanks in advance.....
This may depend on your unusual design.
With INVOICE_ID in ORDR_ and ORDER_ID in INVOICE_ you have both tables at the same time as parent and child of each other.
If your database uses foreign keys deleting and inserting will be hard.
You should use one type/table as parent, (e. g. Order, because it's normaly first) and the other as child (order_id will be in invoice_ table).
In your object model you can have both directions (see first example of http://docs.oracle.com/javaee/6/api/javax/persistence/OneToOne.html)
The issue is incorrect scenario in which you used your Entities/Tables and the one-to-one mapping style. The concept of One-To-One does not corresponed with your current design of both tables and entities.
Please, try to read more about one-to-one here: The concept for one-to-one mapping. Explain the mapping
And mostly take a deep look here: Hibernate – One-to-One example (Annotation), where you can find examples of the one-to-one mapping.
If you really would like to continue with one-to-one mapping you have to:
Remove the "INVOICE_ID" column from the "INVOICE_" table (surprising but a fact)
make the "ORDER_ID" column in the "INVOICE_" table as a primary key (another fact)
change the mapping of the Invoice entity to be more submissive (driven by Order entity)
Example of changes of the Invoice mapping:
// just a draft, to give you idea about the
// "submissive" side mapping.
// All the ID stuff of the Invoice is driven by its
// "Master" - Order
#GenericGenerator(name = "generator", strategy = "foreign",
parameters = #Parameter(name = "property", value = "order"))
#Id
#GeneratedValue(generator = "generator")
#Column(name = "ORDER_ID", unique = true, nullable = false)
public Integer getOrderId() {
return this.orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
public Order getOrder() {
return this.order;
}
Please, take it as a draft, to show how different the one-to-one concept is.
I've a problem with JPA, whenever execute this query
#NamedQuery(name = "Usuario.getUsuarioIntento", query = "SELECT u.intentos_id FROM Usuario u WHERE u.username = :username and u.borrado = 0")
i get this error:
java.lang.IllegalArgumentException: NamedQuery of name: Usuario.getUsuarioIntento not found.
But if i execute this query
#NamedQuery(name = "Usuario.getUsuarioIntento", query = "SELECT u.id FROM Usuario u WHERE u.username = :username and u.borrado = 0")
Work fine,Why?
My table,Usuario:
MY USER TABLE
i try with other column as 'superusuario','version_jpa' and doesn't work, the only columns that work fine are 'id,'borrado' and 'username'
Class Usuario:
#Temporal(TemporalType.TIMESTAMP)
private Date fechaCreacion;
#Id
#GeneratedValue (strategy=GenerationType.AUTO)
private int id;
#OneToOne(cascade = CascadeType.ALL)
private Password password;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH}, fetch = FetchType.LAZY)
private List<Password> clavesAntiguas;
#OneToOne
private Persona persona;
private String sessionId;
private String username;
#ManyToOne(cascade = CascadeType.REFRESH)
private Rol rol;
#ManyToOne(cascade = CascadeType.REFRESH)
private Perfil perfil;
#OneToOne (cascade = CascadeType.ALL)
private IntentosBloqueo intentos;
private boolean superUsuario;
private int borrado;
private int esManager;
#OneToMany ( cascade = {CascadeType.ALL} , fetch = FetchType.LAZY)
private Collection<UsuarioSociedad> sociedades;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
#JoinTable (name="USR_UND_VIS",
joinColumns={
#JoinColumn (name="ID_USU", table="USUARIO", referencedColumnName="ID"),
},
inverseJoinColumns=
#JoinColumn (name="ID_UNI", table="UND_ORG", referencedColumnName="ID")
)
private List<UnidadOrganizativa> unidadesVisibles;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.REFRESH)
#JoinTable (name="USR_UND_DIS",
joinColumns={
#JoinColumn (name="ID_USU", table="USUARIO", referencedColumnName="ID"),
},
inverseJoinColumns=
#JoinColumn (name="ID_UNI", table="UND_ORG", referencedColumnName="ID")
)
private List<UnidadOrganizativa> unidadesDisponibles;
Because Named query works on Entity objetc not on datbase column. You try to find another entity object which contains that id. In That case your named query will give you the object of that entity class and from that object u can get the id or whtever fiels of that entity.
JPA named query is not like SQL or oracle query.
Iin in DB your column name is xyz but in entity your column name is ABC then you have to fetch ABC in named query not XYZ.