Why doesn't Eclipselink generate the ON DELETE CASCADE clause in a unidirectional #ManyToOne relationship? - jpa

These are two related entities in Eclipselink JPA:
#Entity
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
#ManyToOne(cascade={CascadeType.ALL})
private Department department;
}
and this is the generated DDL:
CREATE TABLE PERSON (ID BIGINT IDENTITY NOT NULL, FIRSTNAME VARCHAR, LASTNAME VARCHAR, DEPARTMENT_ID BIGINT, PRIMARY KEY (ID))
CREATE TABLE DEPARTMENT (ID BIGINT IDENTITY NOT NULL, NAME VARCHAR, PRIMARY KEY (ID))
ALTER TABLE PERSON ADD CONSTRAINT FK_PERSON_DEPARTMENT_ID FOREIGN KEY (DEPARTMENT_ID) REFERENCES DEPARTMENT (ID)
The environment is:
- eclipselink 2.5.2
- mysql-connector-java 5.1.6
I would expect to have at least a ON DELETE CASCADE clause on the foreign key definition.
What is the cascade option intended for, in the #ManyToOne relationship?
Do I really have to delete the children records manually before deleting the parent record?

The CascadeType you mention in your example is one value of those: ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH. This is ORM, but not SQL DDL related.
I guess You are searching for a SQL DDL foreign key constraint definition ...on delete cascade. To geht this SQL DDL generated, You need an #CascadeOnDelete annotation, as shown in this example:
...
#OneToMany(mappedBy="abc", orphanRemoval=true, cascade={CascadeType.ALL})
#CascadeOnDelete
private List<MobilPhoneNumer> mobilePhonesNumbers;
...

Related

How would I use an autogenerated primary key which is also a foreign key of another table to insert data using JPA?

I have two tables. The structure is
Personal table
Auto Id Number, int, Primary Key |
Name, Varchar |
Age, int |
Demographic table
Auto id number, int, foreign key |
Address, varchar |
I've created entity classes as below:
PersonalEntity.class
#Entity
#Table("Personal")
public class PersonalEntity {
#Id
#Column(name="Auto Id Number")
private int id;
#Column(name="Name")
private String name;
#Column(name="Age")
private int age;
#OneToOne(cascade=CascadeType.ALL)
#PrimaryKeyJoinColumn
private DemographicEntity de;
DemographicEntity.class
#Id
#Column(name="Auto Id Number")
private int id;
#Column(name="Address")
private String address;
Dao Class
#Transactional
public PersonalEntity add(PersonalEntity pe, DemographicEntity de){
pe.setDe(de);
entitymanager.persist(pe);
return pe;
}
I am using jpa with Microsoft SQL. I want to insert data into the Personal table first and the db will auto generate a primary key. That primary key is the foreign key of Demographic table. When I called the persist() I am getting the error
The INSERT statement conflicted with the FOREIGN KEY constraint. could
not execute statement; contraint(null)
What am I doing wrong here? I want to insert data in the personal table and using the auto generated key, I want to insert data in the demographic table
You have to set optional=false on the OneToOne mapping to tell Hibernate that the FK may not be null
#OneToOne(cascade=CascadeType.ALL, optional=false)

Foreign Key violation on ManyToMany with inheritance

Im currently building the following scenario:
I have an Action which holds a list of Parameters. Those can be in other actions as well, so I have a ManyToMany relationship.
The Parameter is an abstract class, one implementation is a TextParameter.
So now I have the following code:
#Data
#Entity
public class Action {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "Action2ParameterMapping",
joinColumns = #JoinColumn(name = "actionId"),
inverseJoinColumns = #JoinColumn(name = "parameterId"))
private List<Parameter> parameters;
}
with Parameter as
#Data
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class ProductSample {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
}
And TextParameter:
#Data
#Entity
#PrimaryKeyJoinColumn(name = "parameterId")
public class TextParameter extends Parameter {
...
}
I now created the Tables as follows (I don't want to generate since we use Flyway migration):
CREATE TABLE Action
(
id BIGINT NOT NULL PRIMARY KEY IDENTITY
)
CREATE TABLE Parameter
(
id BIGINT NOT NULL PRIMARY KEY IDENTITY
)
CREATE TABLE TextParameter
(
parameterId BIGINT NOT NULL FOREIGN KEY REFERENCES Parameter (id)
)
-- Many-To-Many MappingTable
CREATE TABLE Action2ParameterMapping
(
actionId BIGINT NOT NULL FOREIGN KEY REFERENCES Action (id),
parameterId BIGINT NOT NULL FOREIGN KEY REFERENCES Parameter (id),
PRIMARY KEY (actionId, parameterId)
)
I use Quarkus and have the simple PanacheRepository
#ApplicationScoped
public class ActionRepository implements PanacheRepository<Action> {
}
So now, when I now create an Action-Object holding Parameter-Objects and persist it using actionRepository.persist(action), I get an SQLServerException The INSERT statement conflicted with the FOREIGN KEY constraint "FK__Action2Pa__actio__4242D080 and I don't understand why.
I understand that it tries to tell me, that it wanted to persist an entry in the MappingTable but the actionId did not belong to any Action, but how can that be?
I don't understand, why this won't work.
After having the problem for over 3 days, I've solved almost right after asking the question...
The problem was within the DB-Test-Suite.
The #AfterEachmethod tried to delete parameters, which violated the Contraint...

how to store one table primary as an another table foreign key using one-to-one relationship

I have two entities with one to one relationship, I want parent entity primary as a child entity foreign key along with child entity primary key
I have been trying with JPA #MapsId() but I could not succeed
my parent entity
#Id
#SequenceGenerator(initialValue=10000, name = "parent_seq")
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="parent_seq")
#Column(name = "parent_id")
private long parentid;
#OneToOne(mappedBy="parentEntity", cascade = CascadeType.ALL)
private ChildEntity childEntity;
and in my child entity
#SequenceGenerator(initialValue=10000, name = "child_seq")
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="child_seq")
#Column(name = "child_id")
private long childid;
#MapsId("parent_id")
#OneToOne
private ParentEntity parentEntity;
here I would like to create tables using JPA for that I have given
spring.jpa.hibernate.ddl-auto=create
this is working fine but I am expecting that parent_id column should be created inside my childEntity table but it is not creating and the parent_id should be inserted into child tables parent_id column.
When you are going to use #MapsId feature then your 'child' entity should have the 'simple' identifier without any generation. For example:
#Entity
#Table(name = "parents")
public class Parent {
#Id
#GeneratedValue(...)
private Long id;
// other stuff...
}
#Entity
#Table(name = "children")
public class Child {
#Id
private Long id;
#MapsId
#OneToOne(fetch = FetchType.LAZY)
private Parent parent;
// other stuff...
}
In this case, the children table will be like the following:
create table children (
parent_id bigint not null constraint children_pkey primary key,
-- other stuff...
constraint fk_children_parent_id foreign key (parent_id) references parents(id)
);
More info: The best way to map a #OneToOne relationship with JPA and Hibernate

JPA: implicity persist #ManyToOne entities

I have a similar table structure to the following:
Table_A(
a_id,
data,
primary key(a_id)
)
Table_B(
b_id,
a_id,
data,
primary key (b_id),
foreign key (a_id) references Table_A(a_id)
)
There is a one to many relationship between Table_A and Table_B. My question is, if I have an entity for each of these tables, where:
Entity Table_A is composed of a list of Table_B entities and
Entity Table_B does not necessarily need a reference to Table_A (just the fields b_id, a_id, data)
is it possible to annotate these entities in a way where I can persist a Table_A entity and the process will implicitly persist all Table_B entities with the value of the new generated Table_A primary key a_id.
Thanks in advance.
Here is what I have essentially . But I get the below exception. Looks like Table_B is being persisted prior to Table_A, therefore no a_id value exists.
#Entity
public class Table_A {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "a_id")
private Integer id;
#OneToMany (cascade = CascadeType.PERSIST)
#JoinColumn(name="a_id")
private List<Table_B> bList;
private String data;
}
#Entity
public class Table_B {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "b_id")
private Integer id;
private String data;
}
ERROR: null value in column "a_id" violates not-null constraint
Detail: Failing row contains (null, Testing, 16)
Yes, with a cascade set to PERSIST on the OneToMany association.
Note that you shouldn't have aId in the B entity. Either make the association bidirectional, and have a field of type TableA, or leave it unidirectional and don't have any field in B mapped to a_id.
EDIT: AFAIR, you need to tell Hibernate that the column is not null, else it tries to insert everything first, and then populate the foreign keys:
#OneToMany (cascade = CascadeType.PERSIST)
#JoinColumn(name="a_id", nullable=false)
private List<Table_B> bList;
#OneToMany(mappedBy = "a_id", cascade = CascadeType.PERSIST)
instead of
#OneToMany(cascade = CascadeType.PERSIST) #JoinColumn(name="a_id")

one-to-one relationship using JPA

I have created two table using JPA. i need to give 1-1 relationship between these tables. Can any one tell me how to give relationship between these tables.
Simply add a column in the table "owning" the relation with a FK constraint. For example:
CREATE TABLE MYENTITYA (
ID BIGINT NOT NULL,
MYENTITYB_ID BIGINT
);
CREATE TABLE MYENTITYB (
ID BIGINT NOT NULL
);
ALTER TABLE MYENTITYA ADD CONSTRAINT SQL100326144838300 PRIMARY KEY (ID);
ALTER TABLE MYENTITYB ADD CONSTRAINT SQL100326144838430 PRIMARY KEY (ID);
ALTER TABLE MYENTITYA ADD CONSTRAINT FKB65AC952578E2EA3 FOREIGN KEY (MYENTITYB_ID)
REFERENCES MYENTITYB (ID);
That would be mapped like this:
#Entity
public class MyEntityA implements Serializable {
private Long id;
private MyEntityB myEntityB;
#Id
#GeneratedValue
public Long getId() {
return this.id;
}
#OneToOne(optional = true, cascade = CascadeType.ALL)
public MyEntityB getEntityB() {
return this.myEntityB;
}
//...
}
#Entity
public class MyEntityB implements Serializable {
private Long id;
#Id
#GeneratedValue
public Long getId() {
return id;
}
//...
}
If the relation between EntityA and EntityB is not optional, then add a NOT NULL constraint.