Spring, Hibernate: "collection owner not associated with session" when trying to delete - java

I have this problem where trying to delete a parent object via crud repository, I'm getting this error message:
"collection owner not associated with session: ClassA.things"
This error appeared after splitting one class into three (two classes extend the main classA), but I haven't done any other changes, I haven't touched this OneToMany relationship. So right now it looks approximately like this:
Class A:
#Table
#Entity(name = "ClassA")
#Inheritance(strategy = InheritanceType.JOINED)
#Getter #Setter #NoArgsConstructor #ToString
public class ClassA {
#Column(name = "ClassA_id")
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#OneToMany(mappedBy = "classA", orphanRemoval = true)
private Collection<Thing> things;
...etc, other fields
}
Class B and C (both extend class A):
#Table
#Entity(name = "ClassB")
#Getter #Setter #NoArgsConstructor
public class ClassB extends ClassA {
#Column(name = "ClassB_id")
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
...etc, other fields
}
#Table
#Entity(name = "ClassC")
#Getter #Setter #NoArgsConstructor
public class ClassC extends ClassA {
#Column(name = "ClassC_id")
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
...etc, other fields
}
And here's the Thing class, which the ClassA has a collection of with #OneToMany relationship:
#Table
#Entity(name = "Ratings")
#Getter #Setter #NoArgsConstructor
public class Thing {
#Column(name = "Thing_id")
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter(value = AccessLevel.PRIVATE)
private int id;
#ManyToOne
#JoinColumn(name = "ClassA_id")
private ClassA classA;
...etc, other fields
}
Finally, here's the controller method where DELETE is being called to delete ClassB, for example:
#Transactional
#DeleteMapping("/delete/{id}")
public ResponseEntity<String> deleteClassB(#PathVariable(name = "id") int id) {
if (classBservice.delete(id)) {
return ResponseEntity.ok().build();
} else {
return ResponseEntity.badRequest().build();
}
}

try to remove the id members from ClassB and ClassC since they are inherited from ClassA.

Related

JPA/Hibernate OneToMany relationship from Embedded entity by non-PK columns

JPA Model:
#Getter
#Setter
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "BASE_RECORD")
public class BaseRecord {
#Id
#Column(name = "DB_ID")
public Long id;
#Embedded
public DeclarantRecord declarant;
}
#Getter
#Setter
#Embeddable
#AllArgsConstructor
#NoArgsConstructor
public class DeclarantRecord {
#Column(name = "DECLARANT_ID")
public String declarantId;
#Column(name = "DECLARANT_IDE")
public String identificationNumber;
#Column(name = "DECLARANT_NAME")
public String name;
#OneToMany(mappedBy = "baseRecord", fetch = FetchType.EAGER)
public List<DeclarantAddress> addresses;
}
#Getter
#Setter
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "ADDRESS_RECORD")
public class DeclarantAddress {
#Id
#Column(name = "DB_ID")
public Long id;
#ManyToOne
#JoinColumn(name = "PERS_ID", referencedColumnName = "DECLARANT_ID")
public BaseRecord baseRecord;
}
When fetching a BaseRecord from DB by using a Spring Boot JPARepository, I receive the following exception:
Caused by: org.hibernate.AnnotationException: referencedColumnNames(DECLARANT_ID) of DeclarantAddress.baseRecord referencing BaseRecord not mapped to a single property
I cannot understand what's wrong and moreover, if I inline the DeclarantRecord in the BaseRecord entity by declaring all the properties in there and moving the exact same relationship declaration in the BaseRecord class, everything works perfectly.
The answer that worked for me:
Move
#Column(name = "DECLARANT_ID") public String declarantId; to BaseRecord class.
The rest can stay the same.

Spring Boot auto generate association table with attibute

I'm auto generating entities within the database which works great using:
spring.jpa.hibernate.ddl-auto=update
Now I need an additional attribute within the association table and I can't figure it out without creating an association entity by hand. The current classes listed below generate an association table without the additional attribute.
The tables I need:
persons:
id
search_requests:
id
search_requests_persons:
person_id
search_request_id
study_id
The classes I currently have (simplified):
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "persons")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long id;
// The following line is what I would need
// private List<Integer> studyIds;
}
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "search_requests")
public class SearchRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long id;
#NonNull
#ManyToMany
private List<Person> persons;
}
I'm using Lombok and Javax Persistence for the annotations.
In order to add additional attributes in your JoinTable, you could manually create your JoinTable entity. e.g:
PersonSearchRequest.java
#Entity
#Table(name = "person_search_request)
#Getter
#Setter
#NoArgsConstructor
public class PersonSearchRequest {
#EmbeddedId
private PersonSearchRequestPK id;
// put your additional attribute here, e.g:
private String attribute1;
private Long attribute2;
#ElementCollection
private List<String> attribute3s;
#Embeddable
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
public static class PersonSearchRequestPK implements Serializable {
#ManyToOne(fetch = FetchType.LAZY)
private Person person;
#ManyToOne(fetch = FetchType.LAZY)
private SearchRequest searchRequest;
}
}
Person.java
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "persons")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long id;
#OneToMany(mappedBy = "id.person")
private List<PersonSearchRequest> personSearchRequests;
}
SearchRequest.java
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "search_requests")
public class SearchRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty(access = JsonProperty.Access.READ_ONLY)
private Long id;
#OneToMany(mappedBy = "id.searchRequest")
private List<PersonSearchRequest> personSearchRequests;
}

Embeddable is null so auditing does not work

I have the following embeddable
#Data
#Embeddable
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class BaseEntity {
#CreatedDate
#Column(name = "created_date")
private LocalDateTime createdDate;
}
Which I embedded into another entity like this
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "room")
#Builder
public class room {
#Id
#GeneratedValue
private UUID id;
#JsonUnwrapped
#Embedded
private BaseEntity baseEntity;
#Column(length = 80, nullable = false)
private String name;
}
Now when I save a room entity the embedded BaseEntity is null and that is why nothing is audited. According to https://docs.spring.io/spring-data/commons/docs/2.4.4/reference/html/#auditing.annotations it should just work like this. How can I fix this behaviour ?
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "room")
#Builder
public class room {
...
#JsonUnwrapped
#Embedded
private BaseEntity baseEntity = new BaseEntity();
...
}

get generated id before writing to db

I have 2 tables, products, and product_photos. I need to insert data to both tables in one transaction.
#Entity
#Table(name = "products", schema = "my_schema")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
...
//getter + setter + constructor
}
#Entity
#Table(name = "product_photos", schema = "my_schema")
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class ProductPhoto {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "product_id")
private Integer productId;
...
}
}
Is there a way to retrieve the id of the Product before writing the entity to DB in order to put it on ProductPhoto (column product_id)?

Hibernate - the custom query did not find the entity by the child parameter for ManyToOne unidirectional relation

I have a problem with retrieving an entity using the child's entity as a search parameter. Entities are related to many to one relationship as unidirectional and each object is fetched as FetchType.LAZY.
When I looking for an entity by a child entity, the result is null. But when I set to fetch as Eager it is correct.
My Entities:
#NoArgsConstructor
#Getter
#Entity
#Table(name = "partner")
public class PartnerEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String login;
public PartnerEntity(String login) {
this.login = login;
}
}
#NoArgsConstructor
#Getter
#Entity
#Table(name = "point")
public class PointEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "partner_Id")
private PartnerEntity partnerEntity;
public PointEntity(PartnerEntity partnerEntity) {
this.partnerEntity = partnerEntity;
}
}
#NoArgsConstructor
#Getter
#Entity
#Table(name = "orer")
public class OrdEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PAYMENT_POINT_ID")
private PointEntity pointEntity;
public OrdEntity(PointEntity pointEntity) {
this.pointEntity = pointEntity;
}
}
#NoArgsConstructor
#ToString
#Getter
#Entity
#Table(name = "BL")
public class BLEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PARTNER_LOGIN", referencedColumnName = "login")
private PartnerEntity partnerEntity;
private String number;
public BLEntity(PartnerEntity partnerEntity, String number) {
this.partnerEntity = partnerEntity;
this.number = number;
}
}
And I looking for BLEntity using OrdEntity child:
final OrdEntity byId = ordRepo.findById(id);
final PartnerEntity partnerEntity = order.getPointEntity().getPartnerEntity();
final BLEntity blEntityResult= blRepo.findOneByNumberAndPartner(number, partnerEntity);
The object partnerEntity is not null, it is correct object.
I got blEntityResult as null but if I change in PointEntity fetch to FetchType.EAGER, blEntityResult is not null(correct).
My custom query in repository below:
public interface BLRepo extends JpaRepository<BLEntity, Long> {
#Query("select b from BLEntity b where b.number = :number and b.partnerEntity= :partner")
BLEntity findOneByNumberAndPartner(#Param("number") String number, #Param("partner") PartnerEntity partner);
}
why does happens, if the partner object being downloaded is not null and is correct?
I think you should add the mapping in both sides,
because of default fetch type for #AllToMany=Lazy and #ManyToAll = Eager.
just add below code inside PartnerEntity.
#OneToMany(mappedBy="partnerEntity" , fetch = FetchType.Eager )
List<BLEntity> blEntity = new ArrayList<>();
I change FetchType into Eager in PointEntity:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "partner_Id")
private PartnerEntity partnerEntity;
And everything is ok, but I don't understand why it does not work with PaymentType.Lazy. When I am looking for:
final PartnerEntity partnerEntity = order.getPointEntity().getPartnerEntity();
I get correct entity "PartnerEntity" which has proper login's field (login'field has value "test").
When I turned logged level to 'TRACE' I saw, Hibernate not binding correct login's parameter, it set null instead "test") why? :)

Categories

Resources