Hibernate cascade save with OneToOne relation - jpa

I have two tables Users
CREATE TABLE `users` (
`id` BIGINT NOT NULL,
PRIMARY KEY (`id`))
and Carts
CREATE TABLE `carts` (
`id` BIGINT NOT NULL,
`user_id` BIGINT,
PRIMARY KEY (`id`))
ALTER TABLE `carts` ADD CONSTRAINT Cart_User_FK
FOREIGN KEY (`user_id`) REFERENCES `users` (`id`);
I create entities for them
#Entity
#Table(name = "users")
public class User{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
private Cart cart;
}
and
#Entity
#Table(name = "carts")
public class Cart{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User user;
}
I try to set cart instance to user and save user
Cart cart = new Cart();
cartRepository.save(cart);
user.setCart(cart);
userRepository.save(user);
but hibernate don't update cart table
repositories extended from SimpleJpaRepository
Could somebody explain me how to update related object?

Related

Spring Boot OneToOne referencedColumnName not applied

I have 2 tables:
CREATE TABLE user_profile (
id VARCHAR(36) PRIMARY KEY,
first_name VARCHAR(255) NOT NULL
);
CREATE TABLE user_phone (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36),
phone_number VARCHAR(255) NOT NULL,
code VARCHAR(10) NOT NULL,
validated_at DATETIME NULL
);
ALTER TABLE user_phone ADD CONSTRAINT user_phone_FK FOREIGN KEY (user_id) REFERENCES user_profile(id) ON DELETE CASCADE;
so child has ID reference to his parent, because if I will delete parent I want this child to be deleted also.
In User class I have:
#Entity
#Table(name = "user_profile")
public class UserProfile {
...
#OneToOne
#JoinColumn(name = "id", referencedColumnName = "user_id")
private UserPhone phoneNumber;
but then when I run it I see in JPA logs:
from
user_profile userprofil0_
where
userprofil0_.id=?
why it looks there by ID ? should be by user_id field. Or I missunderstood smth there..
thanks!
One day later and finally I found the solution.
Its pretty tricky in spring and not maybe so intuitive.
So - from user_phone table Ive removed additional ID column, and now user_id is there primary key, only 1 change in sql.
Then in spring:
in UserProfile:
#OneToOne(mappedBy = "userProfile", cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private UserPhone userPhone;
and in UserPhone:
#Id
#Column(name = "user_id", nullable = false)
#Type(type = "uuid-char")
private UUID id;
#OneToOne(fetch = FetchType.LAZY)
#MapsId
#JoinColumn(name = "user_id")
private UserProfile userProfile;
#PrimaryKeyJoinColumn annotation indicates that the primary key of the UserProfile is used as the foreign key value for the associated UserPhone.

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 auto-generated key not reflected in foreign key of child table

Parent Table:
#Table(name="parent_table_t")
public class ParentTable implements Serializable {
#Id
#Column(name="contact_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer contactId;
---------
---------
#OneToOne (cascade = CascadeType.ALL, mappedBy = "parentTable")
private ChildTable childTable;
}
Child Table:
#Table(name="child_table_t")
public class ChildTable implements Serializable {
#Id
#Column(name="child_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer childId;
#Column(name="contact_id")
private Integer contactId;
#JoinColumn(name="contact_id", referencedColumnName = "contact_id", insertable=false, updatable=false)
#OneToOne(cascade = CascadeType.ALL)
private ParentTable parentTable;
}
My requirement is when contact_id is generated in Parent_table_t, it should be copied into contact_id of child_table_t when saved.
When I am calling saveAndFlush / save on Parent Table Entity, it is:
Generating the auto-increment for Parent->contact_id.
But Child_table_t -> contact_id is always null.
Can someone please help in this.
I am using in-memorty hsqldb with spring-boot and JPA.
You marked the relationship #JoinColumn with insertable=false, updatable=false, likely because you have an integer mapping for the column as well. Unfortunately, these settings prevent JPA from setting it with values from the relationship, which instead is forced to set the column with the value in the contactId attribute.
Put the insertable=false, updatable=false on the #Column instead.

Cannot find column [id] for OneToOne?

#Entity
#Table(name = "users")
public class User extends Model
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public Long id;
#OneToOne(mappedBy= "user", cascade = {CascadeType.ALL})
#JoinColumn(name="info_id",referencedColumnName = "id")
public Info info;
}
#Entity
#Table(name="infos")
public class Info extends Model
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public Long id;
#OneToOne(mappedBy="info",cascade = {CascadeType.ALL})
#JoinColumn(name="user_id", referencedColumnName = "id")
public User user;
}
And in my migration, users table includes a info_id column of bigint type, and infos table includes a user_id column of bigint type.
However, when i run the application, it gives me PersistenceException: Error with the Join on [models.Info.user]. Could not find the matching foreign key for [id] in table[users]? Perhaps using a #JoinColumn with the name/referencedColumnName attributes swapped?
Can anyone provide some insight into what's wrong in my code and how to fix it? Thank you.
Try this,
User Model
#OneToOne
#JoinColumn(name="info_id")
public Info info;
Info Model
#OneToOne
#JoinColumn(name="user_id")
public User user;
You shouldn't use mappedBy along with JoinColumn. See the difference here.