QueryDSL - HHH000104: firstResult/maxResults specified with collection fetch; applying in memory - spring

In my Spring Boot/Data/JPA/QueryDSL application I have a following entities:
#Entity
#NamedEntityGraph(name = "graph.User", attributeNodes = { #NamedAttributeNode("authorities") })
#Table(name = "users")
public class User extends BaseEntity implements UserDetails {
private static final long serialVersionUID = 8884184875433252086L;
#Id
#SequenceGenerator(name = "users_id_seq", sequenceName = "users_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "users_id_seq")
private Long id;
private String username;
....
#JsonIgnore
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "users_authorities", joinColumns = { #JoinColumn(name = "user_id") }, inverseJoinColumns = { #JoinColumn(name = "authority_id") })
private Set<Authority> authorities = new HashSet<Authority>();
....
}
#Entity
#Table(name = "authorities")
public class Authority implements GrantedAuthority {
private static final long serialVersionUID = 6118293571787931020L;
#Id
#SequenceGenerator(name = "authorities_id_seq", sequenceName = "authorities_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "authorities_id_seq")
private Integer id;
#NotEmpty
private String name;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "authorities")
private Set<User> users = new HashSet<User>();
....
}
and a following load method:
#Override
public List<User> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
PageRequest pageRequest = null;
Page<User> page;
int pageIndex = first / pageSize;
if (sortField == null || sortField.isEmpty()) {
pageRequest = new PageRequest(pageIndex, pageSize);
} else {
Sort.Direction direction = sortOrder == SortOrder.ASCENDING ? Sort.Direction.ASC : Sort.Direction.DESC;
pageRequest = new PageRequest(pageIndex, pageSize, new Sort(direction, sortField));
}
Predicate predicate = UserExpressions.lazyPredicate(filters);
page = userService.findAll(predicate, pageRequest);
....
}
After this method invocation I see following debug information:
Hibernate: select count(user0_.id) as col_0_0_ from users user0_ where user0_.id is not null
1266079 WARN o.h.h.i.ast.QueryTranslatorImpl - HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!
Hibernate: select user0_.id as id1_10_0_, authority2_.id as id1_0_1_, user0_.created_date as created_2_10_0_, user0_.updated_date as updated_3_10_0_, user0_.account_non_locked as account_4_10_0_, user0_.age as age5_10_0_, user0_.birthday as birthday6_10_0_, user0_.email as email7_10_0_, user0_.enabled as enabled8_10_0_, user0_.first_name as first_na9_10_0_, user0_.gender as gender10_10_0_, user0_.last_name as last_na11_10_0_, user0_.password as passwor12_10_0_, user0_.username as usernam13_10_0_, authority2_.name as name2_0_1_, authoritie1_.user_id as user_id1_10_0__, authoritie1_.authority_id as authorit2_11_0__ from users user0_ left outer join users_authorities authoritie1_ on user0_.id=authoritie1_.user_id left outer join authorities authority2_ on authoritie1_.authority_id=authority2_.id where user0_.id is not null
As you can see, according to "WARN o.h.h.i.ast.QueryTranslatorImpl - HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!" - pagination is applied in memory that is not completely acceptable in case of thousands records.
How to change my configuration in order to apply pagination at database level ?

Related

Using JpaSpecificationExecutor with EntityGraph

I am using a implementation of JpaSpecificationExecutor and trying to use in the repository the #EntityGraph for select which relationships entity they get in a complex query.
My entities examples (all relationships bidireccional)
#Entity
#Table(name = "trazabilidad_contenedor")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class TrazabilidadContenedor implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "traConSeq")
#SequenceGenerator(name = "traConSeq")
private Long id;
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties(value = "trazabilidadContenedors", allowSetters = true)
private PromoProGesCodLer promoProGesCodeLer;
.
.
.
#Entity
#Table( name = "promo_pro_ges_cod_ler")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class PromoProGesCodLer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties(value = "promoProGesCodLers", allowSetters = true)
private ProGesCodLer procesoGestoraCodLer;
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties(value = "promoProGesCodLers", allowSetters = true)
private Promocion promocion;
.
.
.
#Entity
#Table(name = "promocion")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Promocion implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
.
.
.
#Entity
#Table(name = "pro_ges_cod_ler")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
#NextProGesCodLer
public class ProGesCodLer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pgclSeq")
#SequenceGenerator(name = "pgclSeq")
private Long id;
#OneToMany(mappedBy = "procesoGestoraCodLer")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<PromoProGesCodLer> promoProGesCodLers = new HashSet<>();
#ManyToOne(optional = false)
#NotNull
#JsonIgnoreProperties(value = "proGesCodLers", allowSetters = true)
private ProcesoGestora procesoGestora;
.
.
.
And this is my repository
#Repository
public interface TrazabilidadContenedorRepository
extends JpaRepository<TrazabilidadContenedor, Long>, JpaSpecificationExecutor<TrazabilidadContenedor> {
#EntityGraph (
type = EntityGraph.EntityGraphType.FETCH,
attributePaths = {
"promoProGesCodeLer",
"promoProGesCodeLer.promocion",
"promoProGesCodeLer.promocion.direccion",
"promoProGesCodeLer.promocion.direccion.municipio",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
"promoProGesCodeLer.procesoGestoraCodLer.codLER",
"promoProGesCodeLer.procesoGestoraCodLer.codLER.lerType",
"promoProGesCodeLer.procesoGestoraCodLer.nextProGesCodLer",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora.gestora",
}
)
List<TrazabilidadContenedor> findAll(Specification<TrazabilidadContenedor> var1);
}
The constructor of my Specification‹TrazabilidadContenedor›
protected Specification<TrazabilidadContenedor> createSpecification(TrazabilidadContenedorCriteria criteria) {
Specification<TrazabilidadContenedor> specification = Specification.where(null);
if (criteria != null) {
if (criteria.getPromocionId() != null) {
specification =
specification.and((root, query, builder) ->
builder.equal(
root
.join(TrazabilidadContenedor_.promoProGesCodeLer, JoinType.LEFT)
.join(PromoProGesCodLer_.promocion, JoinType.LEFT)
.get(Promocion_.id),
criteria.getPromocionId()
)
);
}
if (criteria.getGestoraId() != null) {
specification =
specification.and(
(root, query, builder) ->
builder.equal(
root
.join(TrazabilidadContenedor_.promoProGesCodeLer, JoinType.LEFT)
.join(PromoProGesCodLer_.procesoGestoraCodLer, JoinType.LEFT)
.join(ProGesCodLer_.procesoGestora, JoinType.LEFT)
.join(ProcesoGestora_.gestora, JoinType.LEFT)
.get(Gestora_.id),
criteria.getGestoraId()
)
);
}
}
return specification;
}
When i have only one criteria , criteria.getPromocionId() or criteria.getGestoraId() it's OK , but if i use both at the same time i obtain.
Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=generatedAlias2,role=com.cocircular.greenadvisor.domain.PromoProGesCodLer.promocion,tableName=promocion,tableAlias=promocion2_,origin=promo_pro_ges_cod_ler promoproge1_,columns={promoproge1_.promocion_id,className=com.cocircular.greenadvisor.domain.Promocion}}] [select generatedAlias0 from com.cocircular.greenadvisor.domain.TrazabilidadContenedor as generatedAlias0 inner join generatedAlias0.promoProGesCodeLer as generatedAlias1 inner join generatedAlias1.promocion as generatedAlias2 inner join generatedAlias0.promoProGesCodeLer as generatedAlias3 inner join generatedAlias3.procesoGestoraCodLer as generatedAlias4 inner join generatedAlias4.procesoGestora as generatedAlias5 inner join generatedAlias5.gestora as generatedAlias6 where ( generatedAlias0.traceabilityStatus=:param0 ) and ( ( generatedAlias6.id=75304L ) and ( generatedAlias2.id=86754L ) )]
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:138)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1542)
at org.hibernate.query.Query.getResultList(Query.java:165)
at org.hibernate.query.criteria.internal.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:76)
For this i'm usign Hibernate 5.4.15 and Spring-Boot 2.2.7.RELEASE.
Every item, presented in generated sql is bound to be present in graph.
So, let's write a full graph path:
select generatedAlias0
from com.cocircular.greenadvisor.domain.TrazabilidadContenedor as generatedAlias0
inner join generatedAlias0.promoProGesCodeLer as generatedAlias1 ---> promoProGesCodeLer
inner join generatedAlias1.promocion as generatedAlias2 ---> promoProGesCodeLer.promocion
inner join generatedAlias0.promoProGesCodeLer as generatedAlias3 ---> promoProGesCodeLer
inner join generatedAlias3.procesoGestoraCodLer as generatedAlias4 ---> promoProGesCodeLer.procesoGestoraCodLer
inner join generatedAlias4.procesoGestora as generatedAlias5 ---> promoProGesCodeLer.procesoGestoraCodLer.procesoGestora
inner join generatedAlias5.gestora as generatedAlias6 ----> promoProGesCodeLer.procesoGestoraCodLer.procesoGestora.gestora
where ( generatedAlias0.traceabilityStatus=:param0 )
and ( ( generatedAlias6.id=75304L ) and ( generatedAlias2.id=86754L ) )
Here's the provided graph:
attributePaths = {
"promoProGesCodeLer",
"promoProGesCodeLer.promocion",
"promoProGesCodeLer.promocion.direccion",
"promoProGesCodeLer.promocion.direccion.municipio",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
"promoProGesCodeLer.procesoGestoraCodLer.codLER",
"promoProGesCodeLer.procesoGestoraCodLer.codLER.lerType",
"promoProGesCodeLer.procesoGestoraCodLer.nextProGesCodLer",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora",
"promoProGesCodeLer.procesoGestoraCodLer.procesoGestora.gestora" }
Looks to me, that node promoProGesCodeLer.procesoGestoraCodLer is missing from graph

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException

This is my orderservice implementation for creating and saving orders here with the customerid I'm getting customer and customer has a cart and in the cart product list is there and for that product list, I should create an order.
public Order save(int custid) {
Optional<Customer> cust = customerRepo.findById(custid);//here customer is there and inside customer cart is there inside cart medicine list is there.
Cart ct= cust.get().getCart();//getting cart from customer
if(ct.getMedicineList().size()!=0) {//create order only if the medicine list is not empty. there are 8 fields **orderDate,dispatchDate,status,medicineList,totalCost,customer and orderId(GeneratedValue)** I can't set the orderId cuz it is auto generated.
LocalDate todaysDate = LocalDate.now();
LocalDate dispatchdate = todaysDate.plusDays(3);
List<Medicine> orderList= new ArrayList<Medicine>();
List<Medicine> cartList= new ArrayList<Medicine>();
cartList=ct.getMedicineList();
orderList.addAll(cartList);
Order ord = new Order();
ord.setCustomer(cust.get());
ord.setMedicineList(orderList);
ord.setDispatchDate(dispatchdate);
ord.setOrderDate(todaysDate);
ord.setStatus("Placed");
ord.setTotalCost((float)ct.getTotalAmount());
logger.info("Add order to the database");
return orderRepository.save(ord);
}
return null;
}
this is my order controller
#PostMapping("/order/{custid}")
public ResponseEntity<Order> addOrder(#Valid #PathVariable("custid") int custid) {
logger.info("Add order in database");
return new ResponseEntity<>(orderService.save(custid), HttpStatus.OK);
}
this is my medicine Entity
#Data
#RequiredArgsConstructor
#ToString
#Table(name = "medicine")
#Entity
public class Medicine {
#Id
#Column(name = "medicine_id", nullable = false)
#NonNull
#GeneratedValue
private int medicineId;
#NonNull
#Size(min = 3, message = "Minimum charecters in medicine name should be 3.")
#NotEmpty
#Column(unique = true, name = "medicine_name", nullable = false)
private String medicineName;
#NonNull
#Column(name = "medicine_cost", nullable = false)
private float medicineCost;
#NonNull
#Column(name = "mfd", nullable = false)
private LocalDate mfd;
#NonNull
#Column(name = "expiry_date", nullable = false)
private LocalDate expiryDate;
#NonNull
#Column(name = "medicine_quantity", nullable = false)
private int medicineQuantity = 1;
#NonNull
private String medicineCategory;
#NonNull
private String medicineDescription;
#JsonIgnore
#ManyToMany(cascade = CascadeType.ALL, mappedBy = "medicineList",fetch = FetchType.EAGER)
private List<Order> orderList;
}
this is my order Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class Order {
#Id
#Column(name = "orderId")
#GeneratedValue
private int orderId;
#NonNull
private LocalDate orderDate;
#ManyToMany(targetEntity = Medicine.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "ord_med", joinColumns = { #JoinColumn(name = "ord_id") }, inverseJoinColumns = {
#JoinColumn(name = "med_id") })
private List<Medicine> medicineList = new ArrayList<>();
#NonNull
private LocalDate dispatchDate;
#NotEmpty
private float totalCost;
#NonNull
private String status;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="c_ord_fk",referencedColumnName = "customerId")
#NonNull
private Customer customer;
}
here when i try to create order for the list inside cart it gives me [36m.m.m.a.ExceptionHandlerExceptionResolver[0;39m [2m:[0;39m Resolved [org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction]
i'm not sure but i think its because of the id but it is autogenerated. Idk how to create an order object for the list of products or is this the correct way to do it.
Actually I found the answer, all I have to do is when you use ManyToMany mapping the cascade type must be cascade = {CascadeType.MERGE,CascadeType.REFRESH} instead of {cascade = CascadeType.ALL} and it works fine. reference JPA: detached entity passed to persist: nested exception is org.hibernate.PersistentObjectException

Hibernate - Spring - ConstraintViolationException - UniqueConstraint

I'm trying to make some fixtures for my Profile model but every time I'm trying to save it "again" after I did an update, I get this message:
nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
This is my Profile class:
#Entity
#Data
#Builder
#ToString(of = {"birthday", "discordId", "description", "spokenLanguages"})
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "profile", uniqueConstraints = #UniqueConstraint(columnNames = "discordId"))
public class Profile implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idProfile;
private Date birthday;
#Column(name="discordId", insertable=true, updatable=false)
private String discordId;
private String description;
#ElementCollection(fetch = FetchType.EAGER)
private Set<String> spokenLanguages = new LinkedHashSet<String>();
#JsonIgnore
#OneToMany(fetch = FetchType.EAGER)
private Set<ProfileGame> profileGames = new LinkedHashSet<>();
#OneToOne(mappedBy = "profile", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
private User user;
#ManyToOne
private TimeSlot timeSlot;
}
Here is the call:
#Order(7)
#Test
void fillProfileGame() {
List<Profile> profileList = this.profileRepository.findAll();
for (Profile profile : profileList) {
List<Game> gameList = this.gameRepository.findAll();
Collections.shuffle(gameList);
int rndNbGame = new Random().ints(1, 5).findFirst().getAsInt();
for (int i = 1; i <= rndNbGame; i++) {
int rndLevel = new Random().ints(1, 100).findFirst().getAsInt();
int rndRanking = new Random().ints(1, 3000).findFirst().getAsInt();
Game rndGame = gameList.get(0);
gameList.remove(0);
ProfileGame profileGames = new ProfileGame(profile, rndGame, "level-" + rndLevel,
"ranking-" + rndRanking);
this.profileGameRepository.save(profileGames);
this.gameRepository.save(rndGame);
}
this.profileRepository.save(profile);
}
}
So what I understand is that Hibernate won't let me update this object because it has a unique contraint field ?
How do we proceed when we want a field to be unique and still being able to update other fields ?
From the code snippet, what I see is that there are some unique constraints applied on the column 'discordId'.
#Table(name = "profile", uniqueConstraints = #UniqueConstraint(columnNames = "discordId"))
and
#Column(name="discordId", insertable=true, updatable=false)
private String discordId;
As you can see, there is a parameter 'updatable' which is set to false. Therefore, when you are trying to update an already existing object, hibernate is throwing UniqueConstraintViolationException.
To fix this, set 'updatable=true' or remove it altogether and it should work fine.
#Column(name="discordId", insertable=true, updatable=true)
private String discordId;

Why does not it work SequenceGenerator in Spring Boot?

I make a blog on Spring Boot + Spring Date
There is a post, user, comment, and entities that contain links between them.
For each of these 6 entities, I added the annotation
#SequenceGenerator (name = "...", sequenceName = "...", allocationSize = 1)
Also created in the Database additionally hibernate_sequencе
However, the following problems arise.
When I add a post (with id = 1) and delete it, and then create a new post, it is already with id 2, not id 1
When I try to add a comment to it,then throws an error that usually occurs if there is no SequenceGenerator.
Error:
ERROR: insert or update on table "posts_comments" violates foreign key constraint "posts_comments_post_id_fkey"
DETAIL: Key (post_id) = (5) is not present in table
Why?
add comment in CommentService
public void create(Comments new_comment,Long parent_id, String login, int post_id)
{
Users user=userService.findByLogin(login);
Posts post=postsRepository.findById((long) post_id).get();
if((parent_id!=null)&&(commentsRepository.existsById(parent_id)))
{
Comments parentComment=commentsRepository.findById(parent_id).get();
parentComment.getChildComment().add(new_comment);
commentsRepository.save(parentComment);
}
new_comment.setOwnerpost(post);
new_comment.setOwner(user);
commentsRepository.save(new_comment);
}
Comment
#Entity
#Table(name = "comments")
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
public class Comments implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "clientsIdSeq1", sequenceName = "comments_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator="comments_id_seq")
private Long id;
#Column(name = "title")
private String title;
#Column(name = "content")
private String content;
#Column(name = "date_create")
private LocalDate dateCreate;
#Column(name = "count_like")
private Long countLike;
#Column(name = "count_dislike")
private Long counterDislike;
#OneToMany(fetch= FetchType.EAGER,cascade=CascadeType.ALL ,orphanRemoval=true )
#JoinTable(name = "parentchild_comment",
joinColumns = #JoinColumn(name= "parent_id"),
inverseJoinColumns = #JoinColumn(name= "child_id"))
#Fetch(value = FetchMode.SUBSELECT)
private List<Comments> childComment;
#ManyToOne(fetch= FetchType.EAGER,cascade=CascadeType.ALL )
#JoinTable(name = "users_comments",
joinColumns = #JoinColumn(name= "comment_id"),
inverseJoinColumns = #JoinColumn(name= "user_id"))
#JsonIgnoreProperties({"listPost", "listComment"})
private Users owner;
#ManyToOne(fetch= FetchType.EAGER,cascade = {CascadeType.REFRESH })
#JoinTable(name = "posts_comments",
joinColumns = #JoinColumn(name= "post_id"),
inverseJoinColumns = #JoinColumn(name= "comment_id"))
#JsonIgnoreProperties({"listComments"})
private Posts ownerpost;
}
Post
#Entity
#Table(name = "posts")
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
public class Posts implements Serializable {
#Id
#Column(name = "id")
#SequenceGenerator(name = "clientsIdSeq4", sequenceName = "posts_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator ="posts_id_seq" )
private Long id ;
#Column(name = "title")
private String title;
#Column(name = "content")
private String content;
#Column(name = "date_create")
private LocalDate dateCreate;
#Column(name = "count_like")
private Long countLike;
#Column(name = "count_dislike")
private Long counterDislike;
#OneToMany(mappedBy = "ownerpost",fetch= FetchType.EAGER,cascade=CascadeType.ALL,orphanRemoval=true )
#Fetch(value = FetchMode.SUBSELECT)
#JsonIgnoreProperties("childComment")
private List<Comments> listComments;
#ManyToOne(fetch= FetchType.EAGER,cascade=CascadeType.REFRESH)
#JoinTable(name = "users_posts",
joinColumns = #JoinColumn(name= "post_id"),
inverseJoinColumns = #JoinColumn(name= "user_id"))
#JsonIgnoreProperties({"listPost", "listComment"})
private Users owner;
}
User
#Entity
#Table(name = "users")
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
public class Users implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "clientsIdSeq5", sequenceName = "users_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "users_id_seq")
private Long id;
#Column(name = "login")
private String login;
#Column(name = "password")
private String password;
#ManyToOne(optional = false, cascade = CascadeType.REFRESH)
#JoinColumn(name = "position_id")
private Position position;
#OneToMany(mappedBy = "owner",fetch= FetchType.EAGER,cascade=CascadeType.ALL,orphanRemoval=true )
#JsonIgnoreProperties("listComments")
#Fetch(value = FetchMode.SUBSELECT)
private List<Posts> listPost;
#OneToMany(mappedBy = "owner",fetch= FetchType.EAGER,cascade=CascadeType.ALL,orphanRemoval=true )
#JsonIgnoreProperties("childComment")
#Fetch(value = FetchMode.SUBSELECT)
private List<Comments> listComment;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Users)) return false;
Users users = (Users) o;
if (!Objects.equals(id, users.id)) return false;
if (!Objects.equals(login, users.login)) return false;
if (!Objects.equals(password, users.password)) return false;
if (!Objects.equals(position, users.position)) return false;
if (!Objects.equals(listPost, users.listPost)) return false;
return Objects.equals(listComment, users.listComment);
}
#Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (login != null ? login.hashCode() : 0);
result = 31 * result + (password != null ? password.hashCode() : 0);
result = 31 * result + (position != null ? position.hashCode() : 0);
result = 31 * result + (listPost != null ? listPost.hashCode() : 0);
result = 31 * result + (listComment != null ? listComment.hashCode() : 0);
return result;
}
}
my code https://dropmefiles.com/pdv48
Insomnia with with requests https://dropmefiles.com/jPOgB
You mixed the name and the sequence name. The generator attribute must be then name not the sequenceName
#SequenceGenerator(name = "clientsIdSeq1", sequenceName = "comments_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator="clientsIdSeq1")

Delete Operation on Embedded Object Spring JPA

I Have below Entities :
#Entity(name = "USRGRP_MAP")
public class UserGroupMapping {
#Id
#Column(name = "USRGRP_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_GRP_MAP_SEQ")
#SequenceGenerator(sequenceName = "usrgrp_map_seq",allocationSize = 1,name = "USER_GRP_MAP_SEQ")
private Long mappingId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "USER_ID", referencedColumnName = "USER_ID")
private User user;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "USR_GRP_ID", referencedColumnName = "USR_GRP_ID")
private UserGroup group;
#Column(name = "USR_USRGRP_ACT")
private String userGroupAct;
getter/setters
}
#Entity(name = "USER")
public class User {
#Id
#Column(name = "USER_ID")
private Long userId;
#Column(name = "LOGIN_ID")
private String userName;
getter/setters
}
#Entity(name = "USR_GRP")
public class UserGroup {
#Id
#Column(name = "USR_GRP_ID")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_GRP_SEQ")
#SequenceGenerator(sequenceName = "usr_grp_seq",allocationSize = 1,name = "USER_GRP_SEQ")
private long groupId;
#Column(name = "GRP_NM")
private String groupName;
#Column(name = "GRP_DESC")
private String groupDesc;
getter/setters
}
UserGroupMapping contains has many to one relationship with both user and group.
Now I want to do CRUD operation on UserGroupMapping for that I have created repository as below:
public interface UserGroupMappingRepository extends JpaRepository<UserGroupMapping, Long> {
List<UserGroupMapping> findByGroup(UserGroup group);
List<UserGroupMapping> findByUser(User user);
}
Now I want to write delete operation(for particular user and group) on UserGroupMapping without deleting any entry in USER and USR_GRP table , Just need to remove entry from USRGRP_MAP table.
I am trying to achieve it using native query:
#Query(value = "delete from USR_USRGRP_MAP where user_id = :userId and usr_grp_id = :groupId",nativeQuery = true)
void deleteUserGroupMappingByUserAndGroup(#Param("userId") Long userId, #Param("groupId") Long groupId);
Facing Exception Invalid SQL grammar, although query work fine in sql developer.
Below is my service class:
#Service
public class UserGroupMappingServiceImpl implements UserGroupMappingService{
#Autowired
private UserGroupMappingRepository repository;
#Override
public void deleteUserGroupMapping(Long userId, Long groupId) {
repository.deleteUserGroupMappingByUserAndGroup(userId,groupId);
}
}
Could anyone suggest correct way to delete entry from UserGroupMapping without deleting user and group ?
Below is USRGRP_MAP table:
USRGRP_ID USER_ID USR_USRGRP_ID USR_USRGRP_ACT
------------- ---------- ------------- -
41 306106 41 Y
14 108527 14 Y
8 295597 8 N
10 296518 10 Y
11 295597 11 Y
Thanks in advance .
Try to change
#Query(value = "delete from USR_USRGRP_MAP where user_id = :userId and usr_grp_id = :groupId",nativeQuery = true)
void deleteUserGroupMappingByUserAndGroup(#Param("userId") Long userId, #Param("groupId") Long groupId);
To this:
#Modifying
#Query(value = "delete from USR_USRGRP_MAP where user_id = :userId and usr_grp_id = :groupId",nativeQuery = true)
void deleteUserGroupMappingByUserAndGroup(#Param("userId") Long userId, #Param("groupId") Long groupId);
Cheers
~Emil

Resources