Unable to delete entity using Spring Data Jpa - spring-data-jpa

I have a bi-directional mapping between Customer, Order and LineItems. When trying to delete using deleteById method of Spring Data JPA, the entities are not getting deleted and I do not see any exception.
#Entity
#Table(name = "customers")
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Data
public class Customer implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotEmpty(message = "customer name cannot be empty")
private String name;
#Column(unique = true)
#Email(message = "customer email address should be valid email address")
private String email;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JsonManagedReference
private Set<Order> orders;
private String password;
#Data
#NoArgsConstructor
#Builder
#AllArgsConstructor
#EqualsAndHashCode(exclude = {"customer", "lineItems"})
#ToString(exclude = {"customer", "lineItems"})
#Entity
#Table(name = "orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Min(value = 2000, message = "Min order value should be 2000 INR")
#Max(value = 10_000, message = "Max order value can be 10000 INR")
private double price;
#PastOrPresent(message = "Order date cannot be in future")
private LocalDate date;
#ManyToOne
#JoinColumn(name="customer_id", nullable = false)
#JsonBackReference
private Customer customer;
#OneToMany(mappedBy = "order",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true
)
private Set<LineItem> lineItems;
//scaffolding code
// set the bidirectional mapping
public void addLineItem(LineItem lineItem){
if(this.lineItems == null){
this.lineItems = new HashSet<>();
}
this.lineItems.add(lineItem);
lineItem.setOrder(this);
}
}
#Data
#NoArgsConstructor
#EqualsAndHashCode(exclude = "order")
#ToString(exclude = "order")
#Builder
#AllArgsConstructor
#Entity
#Table(name="line_items")
public class LineItem {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private int qty;
private double price;
private String name;
#JsonIgnore
#ManyToOne
#JoinColumn(name="order_id", nullable = false)
private Order order;
}
this.orderRepository.deleteById(orderId);
Error:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.classpath.ordersapi.model.Customer.orders, could not initialize proxy - no Session\r\n\tat org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:612)\r\n\tat org.hibernate.collection.internal

Related

Exclude some fields of REST Data with Panache

Just having a look at REST Data with Panache wondering if it is possible to exclude some entity fields from beeing exposed by the rest resource, as we need the generated REST resources only for read access pattern.
However, in the docs https://quarkus.io/guides/rest-data-panache I did not find a way to do it.
Looks like it is using Jackson for JSON, so #JsonIgnore should work for you.
#JSonIgnore can be used at the field level, or you can add it on the Getter or Setter if you want only specific parts to be ignored.
#Entity
#Table(name = "order_item")
public class OrderItem extends PanacheEntityBase {
#Id
#GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
#GeneratedValue(generator = "uuid")
#Column(name = "id", length = 36, nullable = false)
#Getter
#Setter
private String id;
#Getter
#Setter
#ManyToOne(targetEntity = Order.class)
#JsonIgnore
#JoinColumn(name = "order_id")
private Order orderId;
#Getter
#Setter
#JsonIgnore
#ManyToOne(targetEntity = Item.class)
#JoinColumn(name = "item_id")
private Item itemId;
#Getter
#Setter
#Column(name = "quantity", nullable = false)
private Integer quantity;
#Getter
#Setter
#Column(name = "price_total", nullable = false)
private Double priceTotal;
#Getter
#Setter
#Column(name = "note", columnDefinition = "text")
private String note;
}
Or you can use #JsonIgnoreProperties at the top level of the class:
#Entity
#JsonIgnoreProperties(value = { "creator", "created" }, allowSetters = false, allowGetters = true)
public class UpdateUserDeviceTokenRequest extends PanacheEntity {
#NotNull
#NotEmpty
#NotBlank
public String userDeviceToken;
#ManyToOne()
#JoinColumn(name = "creatorUser", insertable = true, updatable = false)
public AppUser creator;
#Column(insertable = true, updatable = false)
public LocalDateTime created;
public UpdateUserDeviceTokenRequest() {
}
#PrePersist
void onCreate() {
this.created = LocalDateTime.now();
}
public UpdateUserDeviceTokenRequest(#NotNull #NotEmpty #NotBlank String userDeviceToken) {
super();
this.userDeviceToken = userDeviceToken;
}
}
Please see https://github.com/quarkusio/quarkus/issues/10339 for possible issue that might arise

Pagerequest object with sort property of the child

How to specify the children's property name while creating the PageRequest object. In the below example, I want to sort based on the name property of the Customer entity which is part of the Order class. I should be able to sort on any of the parent or child field.
Sort.Direction sortDirection = direction
.equalsIgnoreCase("asc") ? Sort.Direction.ASC : Sort.Direction.DESC;
//how to make the `name` property map to `Customer` name
PageRequest pageRequest = PageRequest.of(page, size, sortDirection, "name");
Page<Order> pageResponse = this.orderRepository.findAll(pageRequest);
#Entity
#Table(name = "orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name="customer_id", nullable = false)
#JsonBackReference
private Customer customer;
...
----------
#Entity
#Table(name = "customers")
#NoArgsConstructor
public class Customer implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotEmpty(message = "customer name cannot be empty")
private String name;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JsonManagedReference
private Set<Order> orders;
...

Hibernate #OneToMany where discriminatorValue = 'SOMETHING'

Table pdp_billable_field_state carries configuration for various fields.
Owner of configuration can be any number of Entity`s
This configuration is same for each entity that matches the #DiscriminatorValue
#Getter
#Setter
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "entity_type")
#Table(name = "pdp_billable_field_state")
public abstract class EntityFieldStateJpa extends AuditableJPA {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne
#JoinColumn(name = "status_id")
private StatusJpa status;
#Column(name = "field", columnDefinition= "varchar(255)")
private String field;
private boolean disabled;
private boolean hidden;
}
#DiscriminatorValue("PURCHASE")
public class PurchaseEntityFieldStateJpa extends EntityFieldStateJpa {}
#Getter
#Setter
#Entity
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "pdp_purchase")
public class PurchaseJpa {
// omitted
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
// i do not have a join_column since all records with entity_type PURCHASE map to all purchases, as these are configurations used by all purchases. Should i try and introduce #JoinTable maybe?
#Where(clause = "entity_type='PURCHASE'")
private List<PurchaseEntityFieldStateJpa> fieldStates;
}

Reuse a composite key for a child + a new field

I use spring boot, with jpa (hibernate) and postgresql
I use composite key.
#Entity
#IdClass(SamplingsPK.class)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Samplings {
#Id
#GeneratedValue
private Integer id;
#Id
private int year;
#OneToMany(mappedBy = "sampling", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Samples> samples = new ArrayList<>();
...
}
public class SamplingsPK implements Serializable {
private Integer id;
private int year;
public SamplingsPK(Integer id, int year) {
this.id = id;
this.year=year;
}
private SamplingsPK(){
}
#PrePersist
public void prePersist() {
year = LocalDate.now().getYear();
}
}
#Entity
public class Samples {
#Id
#SequenceGenerator(name = "samples_id_seq", sequenceName = "samples_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "samples_id_seq")
private Integer id;
private String sampleLetter;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "sampling_id", referencedColumnName = "id"),
#JoinColumn(name = "sampling_year", referencedColumnName = "year")
})
private Samplings sampling;
}
That work fine
Instead of having an sequence in samples, I would like to have a composite key... SamplingsPK + sampleLetter.
Is it possible to do it, how to save a sample?
This is a "derived identity", so Samples could be mapped with an #IdClass like this:
#Entity
#IdClass(SamplesPK.class)
public class Samples {
#Id
#ManyToOne
#JoinColumns({
#JoinColumn(name = "sampling_id", referencedColumnName = "id"),
#JoinColumn(name = "sampling_year", referencedColumnName = "year")
})
private Samplings sampling;
#Id
private String sampleLetter;
}
public class SamplesPK {
SamplingsPK sampling; // matches name of attribute and type of Samplings PK
String sampleLetter; // matches name and type of attribute
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.

Hibernate error: mappedBy reference an unknown target entity property

I am having an issue in setting up a many to many relationship in my entities. And I don't understand why
failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: cardgame.bean.User.card in cardgame.bean.Card.users
My Entities:
#MappedSuperclass
#Data
public class BaseEntity implements Serializable {
#Id
#Column(name = "id", nullable = false, unique = true)
private String id;
public BaseEntity() {
this.id = UUID.randomUUID().toString();
}
}
My user emtity:
#Data
#Entity
#Table(name = "users")
public class User extends BaseEntity {
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "uuid", nullable = false)
private String uuid;
#Column(name = "email", nullable = false, unique = true)
private String email;
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Card> cards;
#Column(name = "isActive", nullable = false)
private boolean isActive;
}
My card entity:
#Data
#Entity
#Table(name = "cards")
public class Card extends BaseEntity {
#OneToMany(mappedBy = "card")
private List<User> users;
#Column(name = "strength", nullable = false)
private int strength;
#Column(name = "isActive", nullable = false)
private boolean isActive;
}
The users and cards tables have a many-to-many relationship via user_card table:
#Data
#Entity
#Table(name = "user_card")
public class UserCard implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "user_id", nullable = false)
private User user;
#Id
#ManyToOne
#JoinColumn(name = "card_id", nullable = false)
private Card card;
#Column(name = "cardCount", nullable = false)
private int cardCount;
}
What am i doing incorrect. Please help me