Hibernate deleting parent objects when trying to delete child - java

I am having self join table CATEGORY. When I am trying to delete child entries, my parent entries ae also getting deleted. I am using Oracle 19.3 Db.
Eg.
[
{
"id": 5,
"name": "parent",
"display_name": "parent",
"parent_id": 0
},
{
"id": 6,
"name": "child",
"display_name": "child",
"parent_id": 5
}
]
Upon deleting entry with 6, entry of id 5 is also getting deleted.
My Class
#Entity
#Table(name="CATEGORY")
public class Category implements Serializable {
#Id
#Column(name = "id", nullable = false, updatable = false, unique = true)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "name", nullable = false, updatable = true, unique = false)
private String name;
#Column(name = "display_name", nullable = false, updatable = true, unique = false)
private String displayName;
#NotFound(action = NotFoundAction.IGNORE)
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name="parent_id")
private Category parent;
//Setter and Getters and Constructors
Logs from Spring boot are as follow
2021-04-30 14:50:57.345 DEBUG 2588 --- [nio-8080-exec-3] org.hibernate.SQL :
delete
from
category
where
id=?
2021-04-30 14:50:57.345 TRACE 2588 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [4]
2021-04-30 14:50:57.403 DEBUG 2588 --- [nio-8080-exec-3] org.hibernate.SQL :
delete
from
category
where
id=?
2021-04-30 14:50:57.405 TRACE 2588 --- [nio-8080-exec-3] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [3]
2021-04-30 14:50:57.518 INFO 2588 --- [nio-8080-exec-3] c.e.c.service.impl.CategoryServiceImpl : Course category deleted with chain

You can try to look into your #Cascade annotation with hibernate. It cascades operation between related entities and it looks you are cascading all actions.
cascade={CascadeType.ALL}, which all includes CascadeType.REMOVE.
Refer: https://www.educba.com/cascade-in-hibernate/

Related

Hibernate JPA - Wrongly generated insert statement

Hibernate is generating wrong insert statement - wrong column binding - for the following entity model with single table inheritance and composite primary key using #IdClass.
Wondering if this is a Hibernate bug.
Stack: Spring Boot 2.7 / H2
Superclass base entity - AbstractMemberEvent:
#Entity
#Table(name = "MEMBER_EVENTS")
#Getter
#FieldDefaults(level = AccessLevel.PRIVATE)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "EVENT_TYPE")
#NoArgsConstructor
#IdClass(MemberEventId.class)
public abstract class AbstractMemberEvent {
#Id
#Column(name = "USID")
String usid;
#Id
#Column(name = "UPDATED")
Long eventTime;
#Id
#Column(name = "EVENT_TYPE", insertable = false, updatable = false )
String eventType;
Subclass entity - NewMemberJoined
#Entity
#Getter
#Setter
#FieldDefaults(level = AccessLevel.PRIVATE)
#DiscriminatorValue("NEWMEMBERJOINED")
#NoArgsConstructor
public class NewMemberJoined extends AbstractMemberEvent{
#Column(name="PAYLOAD")
NewMemberJoinedInfo newMemberJoinedInfo;
The IdClass
#Getter
#FieldDefaults(level = AccessLevel.PRIVATE)
#NoArgsConstructor
#EqualsAndHashCode
public class MemberEventId implements Serializable {
String usid;
Long eventTime;
String eventType;
}
From the logs I see that the wrong values are bound to the parameters
Hibernate:
create table member_events (
event_type varchar(31) not null,
updated bigint not null,
usid varchar(255) not null,
payload varchar(255),
primary key (updated, event_type, usid)
)
...
Hibernate:
insert
into
member_events
(payload, event_type, updated, usid)
values
(?, ?, ?, ?)
2022-11-25 21:52:13.789 DEBUG 527088 --- [ restartedMain] tributeConverterSqlTypeDescriptorAdapter : Converted value on binding : ...
2022-11-25 21:52:13.790 TRACE 527088 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [{"firstName":"Jasper" ...}]
2022-11-25 21:52:13.790 TRACE 527088 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [BIGINT] - [1388534400000]
2022-11-25 21:52:13.790 TRACE 527088 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [VARCHAR] - [NEWMEMBERJOINED]
2022-11-25 21:52:13.790 TRACE 527088 --- [ restartedMain] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [VARCHAR] - [3060001234567]
2022-11-25 21:52:13.794 WARN 527088 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 22018, SQLState: 22018
2022-11-25 21:52:13.794 ERROR 527088 --- [ restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper : Data conversion error converting "'NEWMEMBERJOINED' (MEMBER_EVENTS: ""UPDATED"" BIGINT NOT NULL)"; SQL statement:
insert into member_events (payload, event_type, updated, usid) values (?, ?, ?, ?) [22018-214]7'

Hibernate Oracle12c Identity : mysterious problem

I’m trying to configure an existing Spring Boot application to use an Oracle12c database, and I’ve got a problem with Identity columns.
Oracle12c supports identities natively, and i set the strategy as IDENTITY, but hibernate seems to ignore my identity column and try to use
select hibernate_sequence.nextval from dual
I hope someone can help me.
Thanks
This is the log:
Hibernate: select userlogini0_.id as id1_0_, userlogini0_.created_date as created_date2_0_, userlogini0_.register_number as register_number3_0_, userlogini0_.session_id as session_id4_0_, userlogini0_.session_status as session_status5_0_, userlogini0_.updated_date as updated_date6_0_, userlogini0_.user_bank as user_bank7_0_, userlogini0_.user_name as user_name8_0_, userlogini0_.user_structure as user_structure9_0_ from user_login_info userlogini0_ where userlogini0_.register_number=? and userlogini0_.user_name=? and userlogini0_.user_bank=? and userlogini0_.user_structure=? and userlogini0_.session_status=?
Hibernate: insert into user_login_info (created_date, register_number, session_id, session_status, updated_date, user_bank, user_name, user_structure) values (?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select hibernate_sequence.nextval from dual
2021-03-03 20:39:23.707 WARN 8 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 2289, SQLState: 42000
2021-03-03 20:39:23.707 ERROR 8 --- [nio-8080-exec-1] o.h.engine.jdbc.spi.SqlExceptionHelper : ORA-02289: sequence does not exist
2021-03-03 20:39:23.724 ERROR 8 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/be-profiling-clm] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet] with root cause
oracle.jdbc.OracleDatabaseException: ORA-02289: sequence does not exist
These are my configs:
org.hibernate.Version : HHH000412: Hibernate Core {5.3.7.Final}
o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.Oracle12cDialect
This is one of the tables:
CREATE TABLE user_login_info
(
id NUMBER(19,0) GENERATED ALWAYS AS IDENTITY INCREMENT BY 1 START WITH 1 NOT NULL ,
created_date TIMESTAMP (6) NOT NULL ,
register_number VARCHAR2(255 CHAR) NOT NULL ,
session_id VARCHAR2(255 CHAR) NOT NULL ,
session_status VARCHAR2(255 CHAR) NOT NULL ,
updated_date TIMESTAMP (6) NOT NULL ,
user_structure VARCHAR2(255 CHAR) NOT NULL ,
PRIMARY KEY (id)
);
and this is my entity:
#Data
#Entity
#Table(name = "user_login_info")
public class UserLoginInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false, updatable = false)
private Long id;
#Column(name = "REGISTER_NUMBER", nullable = false, updatable = false)
private String registerNumber;
#Column(name = "USER_NAME", nullable = false, updatable = false)
private String userName;
#Column(name = "USER_STRUCTURE", nullable = false, updatable = false)
private String userStructure;
#Column(name = "SESSION_ID", unique = true, nullable = false, updatable = false)
private String sessionId;
#Column(name = "SESSION_STATUS", nullable = false)
#Enumerated(EnumType.STRING)
private SessionStatus sessionStatus;
#Column(name = "CREATED_DATE", nullable = false, updatable = false)
private LocalDateTime createdDate;
#Column(name = "UPDATED_DATE", nullable = false)
private LocalDateTime updatedDate;
}

JPA #AutoGenerated on primary key uses parent sequence/auto incerement for nested entity

in my Spring Boot application I'm trying to save an Entity with a few nested Entities that have a one-to-many relationship. I'm using JPA and Hibernate to save them to a MySQL database.
On the primary keys, I am using #GeneratedValue(strategy = GenerationType.AUTO) on a Long to automatically create values for new entities. This worked for some time, however recently I'm getting an error when trying to save the entity:
java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '282' for key 'PRIMARY'
This is what my entities look like:
Question.java
#Entity
#Table(name = "question")
public class Question {
private Long id;
private List<Answer> answers;
// other fields
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
#OneToMany(mappedBy = "question", cascade = CascadeType.ALL, orphanRemoval = true)
public List<Answer> getAnswers() { return answers; }
public void setAnswers(List<Answer> answers) { this.answers = answers; }
}
Answer.java
#Entity
#Table(name = "answer")
public class Answer {
private Long id;
private Question question;
// other fields
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
#ManyToOne
#JoinColumn(name = "question_id")
public Question getQuestion() { return question; }
public void setQuestion(Question question) { this.question = question; }
}
Repositories are simply:
public interface QuestionRepository extends JpaRepository<Question, Long>{ ... }
Now let's say I am adding a new Question via a web form, including 4 Answers. When calling the repository simply like:
questionRepository.save(question);
After some investigation, it appears that Hibernate is using the auto increment value from the question table for the answers entities, which doesn't work because it already exist.
Trace output log:
Hibernate: insert into question (id) values (?)
2019-08-31 18:47:49.652 TRACE 11516 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [6] as [BIGINT] - [281]
Hibernate: insert into answer (question_id, id) values (?, ?)
2019-08-31 18:47:49.688 TRACE 11516 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [BIGINT] - [281]
2019-08-31 18:47:49.688 TRACE 11516 --- [nio-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [BIGINT] - [282]
2019-08-31 18:47:49.746 WARN 11516 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 1062, SQLState: 23000
2019-08-31 18:47:49.746 ERROR 11516 --- [nio-8080-exec-6] o.h.engine.jdbc.spi.SqlExceptionHelper : Duplicate entry '282' for key 'PRIMARY'
2019-08-31 18:47:49.748 ERROR 11516 --- [nio-8080-exec-6] o.h.i.ExceptionMapperStandardImpl : HHH000346: Error during managed flush [org.hibernate.exception.ConstraintViolationException: could not execute statement]
2019-08-31 18:47:49.847 ERROR 11516 --- [nio-8080-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '282' for key 'PRIMARY'
I've verified that the auto_increment value on the answer table is 581.
What could be the cause of this? Is there property/configuration I'm missing?
Since MySQL doesn't support sequences natively so this issue might occur when #GeneratedValue(strategy = GenerationType.AUTO) is used.
Use the below workaround for id generation.
#Id
#GeneratedValue(
strategy= GenerationType.AUTO,
generator="native"
)
#GenericGenerator(
name = "native",
strategy = "native"
)
Please refer https://hibernate.atlassian.net/browse/HHH-11014 for further details.
You can also refer ::: https://vladmihalcea.com/why-should-not-use-the-auto-jpa-generationtype-with-mysql-and-hibernate/

Can we use LAZY LOADING on One-to-many Relationship in Hibernate 5?

I tried to use LAZY LOADING when loading information of Match without list of live links. But the result always fetch all links in Match.
My question is:
Is it possible to use LAZY LOAD for One-to-many relationship in Hibernate 5? If we can, please help me to check my code.
Thank you very much!
I have following code:
#Entity
#Table(name = "match_info")
public class MatchInfoModel extends AuditModel {
#Id
#Column(name = "MATCH_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long matchId;
#Column(name = "STADIUM_NAME")
private String stadiumName;
#Column(name = "START_TIME")
private Date startTime;
#OneToMany(mappedBy = "matchInfoModel", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
private Set<LiveStreamModel> liveStreamsSet;
}
#Entity
#Table(name = "live_stream")
public class LiveStreamModel extends AuditModel {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "LIVE_LINK_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long liveLinkId;
#Column(name = "LINK")
private String link;
#Column(name = "SPEED")
private String speed;
#Column(name = "ORDER_NUMBER")
private int orderNumber;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "MATCH_ID")
#JsonProperty(access = Access.WRITE_ONLY)
private MatchInfoModel matchInfoModel;
}
My Query function:
#Override
public List<MatchInfoModel> getLiveMatches() throws Exception {
Session session = getSession();
CriteriaBuilder criteria = session.getCriteriaBuilder();
CriteriaQuery<MatchInfoModel> criteriaQuery = criteria.createQuery(MatchInfoModel.class);
Root<MatchInfoModel> matchInfoRoot = criteriaQuery.from(MatchInfoModel.class);
criteriaQuery.select(matchInfoRoot);
// Order by start time
criteriaQuery.orderBy(criteria.asc(matchInfoRoot.get("startTime")));
return session.createQuery(criteriaQuery).getResultList();
}
My TRACE log:
2018-08-13 10:00:24 DEBUG org.hibernate.SQL -
select
matchinfom0_.match_id as match_id1_4_,
matchinfom0_.creat_date as creat_da2_4_,
matchinfom0_.create_user as create_u3_4_,
matchinfom0_.last_modified as last_mod4_4_,
matchinfom0_.modified_user as modified5_4_,
matchinfom0_.guest_team_id as guest_t10_4_,
matchinfom0_.has_live_stream as has_live6_4_,
matchinfom0_.host_team_id as host_te11_4_,
matchinfom0_.league_name as league_n7_4_,
matchinfom0_.stadium_name as stadium_8_4_,
matchinfom0_.start_time as start_ti9_4_
from
match_info matchinfom0_
order by
matchinfom0_.start_time asc
2018-08-13 10:00:25 TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [1]
2018-08-13 10:00:25 DEBUG org.hibernate.SQL -
select
livestream0_.match_id as match_i12_3_0_,
livestream0_.live_link_id as live_lin1_3_0_,
livestream0_.live_link_id as live_lin1_3_1_,
livestream0_.creat_date as creat_da2_3_1_,
livestream0_.create_user as create_u3_3_1_,
livestream0_.last_modified as last_mod4_3_1_,
livestream0_.modified_user as modified5_3_1_,
livestream0_.language as language6_3_1_,
livestream0_.link as link7_3_1_,
livestream0_.link_type as link_typ8_3_1_,
livestream0_.match_id as match_i12_3_1_,
livestream0_.order_number as order_nu9_3_1_,
livestream0_.speed as speed10_3_1_,
livestream0_.status as status11_3_1_
from
live_stream livestream0_
where
livestream0_.match_id=?
2018-08-13 10:00:25 TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [7]
2018-08-13 10:00:25 DEBUG org.hibernate.SQL -
select
livestream0_.match_id as match_i12_3_0_,
livestream0_.live_link_id as live_lin1_3_0_,
livestream0_.live_link_id as live_lin1_3_1_,
livestream0_.creat_date as creat_da2_3_1_,
livestream0_.create_user as create_u3_3_1_,
livestream0_.last_modified as last_mod4_3_1_,
livestream0_.modified_user as modified5_3_1_,
livestream0_.language as language6_3_1_,
livestream0_.link as link7_3_1_,
livestream0_.link_type as link_typ8_3_1_,
livestream0_.match_id as match_i12_3_1_,
livestream0_.order_number as order_nu9_3_1_,
livestream0_.speed as speed10_3_1_,
livestream0_.status as status11_3_1_
from
live_stream livestream0_
where
livestream0_.match_id=?
2018-08-13 10:00:25 TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [1] as [BIGINT] - [6]
Yes, of-course we can use, lazy loading in #OneToMany relationship.
Just do this
#OneToMany(fetch = FetchType.LAZY)
#MapsId
private Set<LiveStreamModel> liveStreamsSet;
More info OnetoOne and OneToMany

What the common behaviour when updating an unidirectional #OneToMany List of objects with Spring Data-JPA?

I have an Object with a List of another object.
It's mapped like this:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "products")
public class Product extends DateAudit {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
#Size(min = 3, max = 30)
private String name;
#NotBlank
private String shortDescription;
#NotBlank
private String description;
#NotNull
private Double regularPrice;
private Double promotionPrice;
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id", nullable = false)
private Category category;
#NotNull
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "store_id", nullable = false)
private Store store;
#Size(max = 20)
private String sku;
private Double weight;
private Integer quantityInStock;
#NotNull
private Boolean notifyLowStock;
#OneToMany(cascade = CascadeType.ALL)
private List<Image> images = new ArrayList<Image>();
On the Image side, that's the maaping:
#Entity
#Table(name = "images")
public class Image {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
private String url;
What happens is:
1. I create my Product object and save it on the database.
2. I update this product object by adding images to it later like this:
Product product = repository.findById(productId);
Image image = new Image();
image.setUrl(url);
product.getImages().add(image);
repository.save(product);
This is what I get on my console everytime I add a new image to the product and save it:
When I add the first image:
2018-07-27 22:46:47.367 DEBUG 8580 --- [nio-5000-exec-3] org.hibernate.SQL : insert into images (url) values (?)
2018-07-27 22:46:48.307 DEBUG 8580 --- [nio-5000-exec-3] org.hibernate.SQL : insert into products_images (product_id, images_id) values (?, ?)
When I add one more image:
2018-07-27 22:47:09.955 DEBUG 8580 --- [nio-5000-exec-4] org.hibernate.SQL : delete from products_images where product_id=?
2018-07-27 22:47:09.957 DEBUG 8580 --- [nio-5000-exec-4] org.hibernate.SQL : insert into products_images (product_id, images_id) values (?, ?)
2018-07-27 22:47:09.958 DEBUG 8580 --- [nio-5000-exec-4] org.hibernate.SQL : insert into products_images (product_id, images_id) values (?, ?)
When I add the third image:
2018-07-27 22:47:32.314 DEBUG 8580 --- [nio-5000-exec-5] org.hibernate.SQL : delete from products_images where product_id=?
2018-07-27 22:47:32.316 DEBUG 8580 --- [nio-5000-exec-5] org.hibernate.SQL : insert into products_images (product_id, images_id) values (?, ?)
2018-07-27 22:47:32.318 DEBUG 8580 --- [nio-5000-exec-5] org.hibernate.SQL : insert into products_images (product_id, images_id) values (?, ?)
2018-07-27 22:47:32.319 DEBUG 8580 --- [nio-5000-exec-5] org.hibernate.SQL : insert into products_images (product_id, images_id) values (?, ?)
My question is:
Is deleting the whole list and adding all of it back to the database the correct behaviour? I was expecting it do just add the new image, leaving the other images there. Instead if remove all images based on the productId and the add it all back again.
I retrieve the product right before updating it.
I retrieve the product, I add the new image to the list and I call the save method.
Is that normal? Is there a way to avoid this delete?
Thanks
In short, this needs either an order in the list, e.g. by Image.url:
#OneToMany(cascade = CascadeType.ALL)
#OrderColumn(name = "url")
private List<Image> images = new ArrayList<>();
or don't worry about the order:
#OneToMany(cascade = CascadeType.ALL)
private Set<Image> images = new HashSet<>();
Either of those eliminates the delete and extra insert against products_images.
The nearest thing I know of to a high-level explanation of this is here, though it's talking about #Embeddable instead of #Entity elements in the collection. It seems like Hibernate should have less issue identifying individual entities (with ids) in a collection, but it doesn't do this for an unsorted List (or PersistentBag in the Hibernate model).

Categories