Is it possible to implement saving changes to child objects in hibernate? - java

I have such entities:
#Entity
#Getter
#Setter
#ToString(of = {"id", "type", "hostId"})
#EqualsAndHashCode(of = {"id", "hostId", "player"})
#NoArgsConstructor
#TypeDef(
name = "pgsql_enum",
typeClass = PostgreSQLEnumType.class
)
public class ContentPlayer implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Content_id")
private Content content;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "player_id")
#JsonView(Views.FullContent.class)
private Player player;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "translation_id")
#JsonView(Views.FullContent.class)
private Translation translation;
#Length(max = 155)
#NotNull
#JsonView(Views.FullContent.class)
private String hostId;
#Enumerated(EnumType.STRING)
#org.hibernate.annotations.Type(type = "pgsql_enum")
#JsonView(Views.FullContent.class)
private TranslationType translationType;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updatedByPlayer;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createdByPlayer;
#CreationTimestamp
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime created;
#OneToOne(mappedBy = "contentPlayer", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
#JsonView(Views.FullContent.class)
private Series series;
}
#Entity
#Getter
#Setter
#ToString(of = {"id", "seasons"})
#EqualsAndHashCode(of = {"id", "episodesTotal", "seasons"})
#NoArgsConstructor
public class Series {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#JsonView(Views.FullContent.class)
private int lastSeason;
#JsonView(Views.FullContent.class)
private int lastEpisode;
#JsonView(Views.FullContent.class)
private int episodesCount;
#JsonView(Views.FullContent.class)
private int episodesTotal;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
#JsonView(Views.FullContent.class)
private LocalDate nextEpisode;
#OneToMany(mappedBy = "series", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JsonView(Views.FullContent.class)
private Set<Season> seasons = new LinkedHashSet<>();
#OneToOne
#MapsId
#JoinColumn(name = "id")
private ContentPlayer contentPlayer;
}
#Entity
#Getter
#Setter
#ToString(of = {"id", "number"})
#EqualsAndHashCode(of = {"id", "number"})
#NoArgsConstructor
public class Season {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#NotNull
#JsonView(Views.FullContent.class)
private int number;
#OneToMany(mappedBy = "season", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JsonView(Views.FullContent.class)
private Set<Episode> episodes = new LinkedHashSet<>();;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "series_id", nullable = false, updatable = false)
private Series series;
}
When I try to save the ContentPlayer with all child entities - everything goes fine, but if I want to add / change some data in the child entity - this leads to an error, although I indicated the cascade.
Error Example:
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.core.entities.content.Season.series -> com.core.entities.content.Series;
Is it possible to implement saving changes to child objects? Adding each child object individually is not really appropriate.

Related

About auto create table in Hibernate Java Spring boot application

I have a small project Java Spring Boot, i use Annotation to create field and Table in MySQL, i want to add some other field in a middle table "candidate_tets" to store some other field, then i create a class "CandidateTest". But when i add annotation #Id and #GeneratedValue(strategy = GenerationType.IDENTITY) in var "id", i have a problem, that the AutoIncrement in MySQL and PRIMARY KEY isn't set to column id in MySQL, i don't know the problem in here
this is my Candidate class
#Entity
#Table(name = "candidate")
#SuppressWarnings("serial")
public class Candidate implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private int id;
#Column
private String name;
#Column(nullable = true)
private int level; // 1 Fresher, 2 Junior, 3 Senior
#Column(unique = true)
private String phone;
#Column(unique = true)
private String email;
#Column(nullable = true)
private String position;// Vi tri ???
#Column(name = "english_mark", columnDefinition = "DOUBLE DEFAULT 0")
private Double englishMark;
#Column(name = "coding_mark", columnDefinition = "DOUBLE DEFAULT 0")
private Double codingMark;
#Column(name = "knowledge_mark", columnDefinition = "DOUBLE DEFAULT 0")
private Double knowledgeMark;
#Column(name = "date_test")
#DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss", iso = ISO.DATE_TIME)
#JsonFormat(shape=JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dates;
#Column(name = "is_done", columnDefinition = "INT DEFAULT 0")
private int isDone;
#ManyToMany(fetch = FetchType.EAGER)
#Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE)
#JoinTable(name = "candidate_Test", joinColumns = {#JoinColumn(name = "id_candidate")},
inverseJoinColumns = {#JoinColumn(name = "id_test")})
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private Set<Test> tests = new HashSet<>();
#Column
private String avatar;
//Constructor , Getter and Setter ...
}
this is test class:
#Entity
#Table(name = "test")
#JsonIgnoreProperties({"hibernateLazyInitializer"})
#SuppressWarnings("serial")
public class Test implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private int id;
#Column
private int subject;
#Column
private int level;
#Column(name = "time")
#DateTimeFormat(pattern = "HH:mm:ss", iso = ISO.TIME)
#JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "HH:mm:ss")
private LocalTime times;
#Column
private String name;
#Column(name = "code_test", unique = true)
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private String codeTest;
#ManyToMany
#JsonIgnore
#JoinTable(name = "candidate_Test", joinColumns = {#JoinColumn(name = "id_test")}, inverseJoinColumns = {#JoinColumn(name = "id_candidate")})
private List<Candidate> candidates = new ArrayList<>();
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "test_question",
joinColumns = {#JoinColumn(name = "id_test")}, inverseJoinColumns = {#JoinColumn(name = "id_question")})
private Set<Question> questions = new HashSet<>();
//Getter and Setter ...
this is candidate_test class:
#Entity
#SuppressWarnings("serial")
#Table(name = "candidate_test")
public class CandidateTest implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private int id;
#Column(name = "id_candidate")
private int candidateId;
#Column(name = "id_test")
private int testId;
#Column(name = "marks", columnDefinition = "DOUBLE DEFAULT 0")
private Double marks;
//Getter and Setter ....
file application.properties
spring.datasource.url = jdbc:mysql://db:3306/testingonline?zeroDateTimeBehavior=convertToNull&autoReconnect=true&useUnicode=yes&characterEncoding=UTF-8
spring.datasource.username= root
spring.datasource.password= 123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.use-new-id-generator-mappings= false
spring.mvc.pathmatch.matching-strategy=ant-path-matcher
springdoc.api-docs.path=/api-docs
spring.mvc.pathpattern.matching-strategy=ant_path_matcher
spring.jackson.serialization.write-dates-as-timestamps=false
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect```
this is MySQL table *candidate_test* and the problem
![enter image description here](https://i.stack.imgur.com/2SWKW.png)
Can you guys give me the reason why the AutoIncrement and PRIMARY KEY is not set in this middle table
I think it is because of the Serializable interface try removing that and then re-execute it should work.

JPA OneToMany delete on parent don't remove linked entities

I'm using SpringBoot and JPA + Hibernate.
I have these entities:
#Entity
#Table(name = "post")
#AllArgsConstructor #NoArgsConstructor
#Getter #Setter
public class Item extends BaseEntity {
#Id
#Column(name = "id")
#Type(type = "uuid-char")
private UUID uuid = UUID.randomUUID();
#OneToMany(mappedBy = "post", orphanRemoval=true, fetch = FetchType.EAGER)
#MapKey(name="userId")
private Map<UUID, Share> shares;
....
#CreationTimestamp
#Column(name = "creation_date")
#Setter(AccessLevel.NONE)
private Instant creationDate;
#UpdateTimestamp
#Column(name = "last_mod_date")
#Setter(AccessLevel.NONE)
private Instant lastModificationDate;
}
#Entity
#Table(name = "comment"
#AllArgsConstructor #NoArgsConstructor
#Getter #Setter
public class Comment extends BaseEntity {
#Id
#Column(name = "id")
#Type(type = "uuid-char")
#Setter(AccessLevel.NONE)
private UUID uuid = UUID.randomUUID();
#ManyToOne(fetch = FetchType.LAZY)
#NotNull()
#JoinColumn(name = "post_id")
private Post post;
.....
#CreationTimestamp
#Column(name = "creation_date")
#Setter(AccessLevel.NONE)
private Instant creationDate;
#UpdateTimestamp
#Column(name = "last_mod_date")
#Setter(AccessLevel.NONE)
private Instant lastModificationDate;
}
#Test
#Transactional
public void testDeleteItem() {
itemRepo.delete(item);
itemRepo.flush();
}
When I try to delete a parent entity (Post), all related entities Comments remains on the database.
Why doesn't works the cascade deletion?
OrphanRemoval doesn't work. Use cascade = CascadeType.ALL instead

How to replace CriteriaBuilder with Spring JPA

I have next classes:
#Entity
#Table
public class Lesson implements ModelEntity {
#Id
#Column(name = "lesson_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "course_id")
private Course course;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lesson_type_id")
private LessonType lessonType;
private LocalDate date;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "time_slot_id")
private TimeSlot timeSlot;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "auditorium_id")
private Auditorium auditorium;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "lesson_teacher", joinColumns = #JoinColumn(name = "lesson_id"), inverseJoinColumns = #JoinColumn(name = "person_id"))
private Set<Teacher> teachers = new HashSet<>();;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "lesson_group", joinColumns = #JoinColumn(name = "lesson_id"), inverseJoinColumns = #JoinColumn(name = "group_id"))
private Set<Group> groups = new HashSet<>();
}
#Entity
#Table(name = "groups")
public class Group implements ModelEntity {
#Id
#Column(name = "group_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "group_name")
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "faculty_id")
private Faculty faculty;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "group")
private List<Student> students;
}
#Entity
#Table
public class TimeSlot implements ModelEntity {
#Id
#Column(name = "time_slot_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "time_slot_number")
private Integer number;
#Column(name = "time_slot_name")
private String name;
#Column(name = "time_slot_start")
private LocalTime startTime;
#Column(name = "time_slot_end")
private LocalTime endTime;
}
I wrote method, that find all Groups_id by Date and TimeSlot_id not connected to Lesson with CriteriaBuilder API, it works perfect:
#Override
public Set<Integer> getBusyGroupsId(int lessonId, LocalDate date, int timeSlotId) {
logger.debug("getBusyGroupsId() with agruments {}, {}, {}.", lessonId, date, timeSlotId);
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Integer> query = criteriaBuilder.createQuery(Integer.class);
Root<Lesson> root = query.from(Lesson.class);
List<Predicate> predicates = new ArrayList<>();
Join<Lesson, TimeSlot> timeSlotJoin = root.join("timeSlot", JoinType.LEFT);
predicates.add(criteriaBuilder.equal(timeSlotJoin.get("id"), timeSlotId));
predicates.add(criteriaBuilder.equal(root.get("date"), date));
if (nonNull(lessonId)) {
predicates.add(criteriaBuilder.notEqual(root.get("id"), lessonId));
}
query.where(predicates.toArray(new Predicate[] {}));
SetJoin<Lesson, Group> joinGroup = root.joinSet("groups");
query.multiselect(joinGroup.get("id"));
TypedQuery<Integer> result = entityManager.createQuery(query);
return result.getResultStream().collect(Collectors.toSet());
}
But after that I think- what about JPA, can it be easier?
I tried something like that, but it doesnt work:
public Set<Integer> findGroupIdByIdNotAndDateEqualsAndTimeSlotIdEquals(Integer lessonId, LocalDate date, Integer timeSlotId);
How to fix it?
Also I stacked with writing method with JPA that should find all Lesson by Group_id and Date(or startDate-endDate) and sort it: first by date, second- by TimeSlot_number.
Can it be written with JPA?
Thanks in advance.
Don't throw stones, I'm just getting to know Spring JPA.

Getting error Parameter value [1465] did not match expected type [java.util.Set (n/a)] while fetchimg data from JPA

I am getting Data from MySql using Spring Data JPA. I getting this error when I am passing provider as 1465 in request.
I have tried Sending Set from the request as well.
My calling code is :
offerList = blackholeDetailRepository.findByProductVMS(ProductType.VMS, blackholeID,
pricingCopyRequestBO.getProviderId().longValue(),
OfferGradeConstant.fromString(pricingCopyRequestBO.getOfferGrade()));
Code in repository is :
#Query("SELECT detail FROM #{#entityName} AS detail JOIN FETCH detail.vmsRestrictedProviders AS provider "+
"WHERE detail.product = :product " + "AND detail.master.id= :masterId "
+ "AND detail.vmsRestrictedProviders = :providerId " + "AND provider.offerGrade= :offerGrade")
Set<BlackholeDetailEntity> findByProductVMS(#Param("product") ProductType product, #Param("masterId") Long masterId,
#Param("providerId") Long providerId, #Param("offerGrade") OfferGradeConstant offerGrade);
BlackholeDetailEntity Entity is :
#Entity
#Table(name = "blackhole_detail")
#Data
#EqualsAndHashCode(callSuper = true)
public class BlackholeDetailEntity extends PolygonDetailEntity {
private static final long serialVersionUID = 1L;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "blackhole_entity_mapping",
joinColumns = #JoinColumn(name = "detail_id", referencedColumnName = "id"))
#Column(name = "entity_id")
private Set<Integer> entities;
#Convert(converter = CsvStringSetConverter.class)
private Set<String> restrictedOffers;
#Convert(converter = CsvLongSetConverter.class)
#Column(name = "ll_me_restricted_providers", columnDefinition = "text")
private Set<Long> llMERestrictedProviders;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL,
orphanRemoval = true, mappedBy = "blackHole")
private Set<VmsProviderRestrictionEntity> vmsRestrictedProviders;
#Column(name = "is_restrict_all")
private Boolean restrictAll;
}
VmsProviderRestrictionEntity is :
#Data
#Entity
#ToString(exclude = {"blackHole"})
#EqualsAndHashCode(exclude = "blackHole")
#Table(name = "vms_provider_blackhole_restriction")
public class VmsProviderRestrictionEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Enumerated(EnumType.STRING)
private OfferGradeConstant offerGrade;
#Convert(converter = CsvLongSetConverter.class)
#Column(name = "vms_restricted_providers", columnDefinition = "text")
private Set<Long> providerIds;
#ManyToOne
#JoinColumn(name = "blackhole_id")
private BlackholeDetailEntity blackHole;
}
PolygonDetailEntity.java
#MappedSuperclass
#Data
#ToString(exclude = {"master","masterPricing"})
#EqualsAndHashCode(callSuper = false, exclude = {"master", "masterPricing"})
public class PolygonDetailEntity extends ModifiableAuditableEntity {
private static final long serialVersionUID = -9100537914314976516L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "master_id")
private PolygonMasterEntity master;
#ManyToOne
#JoinColumn(name = "master_pricing_id")
private PolygonMasterPricingEntity masterPricing;
#Enumerated(EnumType.STRING)
private ProductType product;
private Integer serviceId;
#Column(columnDefinition = "text")
private String comments;
private String accessTechnology;
#Column(name = "is_active")
private Boolean active;
#Column(name = "is_deleted")
private Boolean deleted;
}

Hibernate ORA-02292: integrity constraint (ROOT.SYS_C007062) violated - child record found

I following have hibernate entities:
#Entity
#Table(name = "News")
public final class News implements Serializable, IEntity {
private static final long serialVersionUID = 3773281197317274020L;
#Id
#SequenceGenerator(name = "NEWS_SEQ_GEN", sequenceName = "NEWS_SEQ")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "NEWS_SEQ_GEN")
#Column(name = "NEWS_ID", precision = 0)
private Long newsId; // Primary key
#Column(name = "TITLE")
private String title;
#Column(name = "SHORT_TEXT")
private String shortText;
#Column(name = "FULL_TEXT")
private String fullText;
#Temporal(TemporalType.DATE)
#Column(name = "CREATION_DATE")
private Date creationDate;
#Temporal(TemporalType.DATE)
#Column(name = "MODIFICATION_DATE")
private Date modificationDate;
#OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true)
#JoinColumn(name = "NEWS_ID", updatable = false, referencedColumnName = "NEWS_ID")
#OrderBy("creationDate ASC")
private List<Comment> commentsList;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "NEWS_TAG", joinColumns = { #JoinColumn(name = "NEWS_ID") }, inverseJoinColumns = { #JoinColumn(name = "TAG_ID") })
private Set<Tag> tagSet;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "NEWS_AUTHOR", joinColumns = { #JoinColumn(name = "NEWS_ID") }, inverseJoinColumns = { #JoinColumn(name = "AUTHOR_ID") })
private Set<Author> author;
And the second:
#SequenceGenerator(name = "COMMENTS_SEQ", sequenceName = "COMMENTS_SEQ")
#Entity
#Table(name = "Comments")
public class Comment implements Serializable, IEntity {
private static final long serialVersionUID = 3431305873409011465L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "COMMENTS_SEQ")
#Column(name = "COMMENT_ID", precision = 0)
private Long commentId; // Primary key
#Column(name = "NEWS_ID")
private Long newsId;
#NotEmpty
#NotNull
#Column(name = "COMMENT_TEXT")
private String commentText;
#Temporal(TemporalType.DATE)
#Column(name = "CREATION_DATE")
private Date creationDate;
When I'm trying to remove entity News, I get the exception ORA-02292: integrity constraint (ROOT.SYS_C007062) violated - child record found. So, if I remove the property "updatable = false" it tries to set nullable fields into property Comment. What is my mistake? Please, help.
Thanks.
Because your news records have a one to one or one to many relation with comments. You most likely did not specifcy a CACASDE ON DELETE clause while defining your table. in order to delete entity NEWS you have to make sure that all of its related comments records are deleted or are referencing another NEWS record.
basicaly the definition of the ORA 02292 exception.

Categories

Resources