Problem Retrieving Nextval in JPA Application - spring-boot

I need have a need to return nextVal at various times in my application. I have an entity class like the following:
#Entity
#Table(name = "TBL_CACL")
public class Cacl {
#Id
#SequenceGenerator(name = "caclGenerator", sequenceName = "caclSeq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.IDENTITY, generator = "calcGenerator")
#Column(name = "ID")
private Integer id;
// more stuff below....
, and I added the following in my repository interface:
#Repository
public interface CaclRepository extends JpaRepository<Cacl, Integer> {
#Query(value = "SELECT caclSeq.nextval FROM Cacl", nativeQuery = true)
Long getNextSeriesId();
However when I attempt to read it like this:
long nextval = caclRepository.getNextSeriesId() + 1;
, I get this exception:
(can't show entire stack trace)
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
Caused by: org.postgresql.util.PSQLException: ERROR: relation "cacl" does not exist
Its puzzling to me that I am getting error "cacl does not exist" because this application has been up and working for some time. All that I have done is add the #SequenceGenerator, updated the #GeneratorValue to link to the #SequenceGenerator annotation, and create the new query. I would be grateful for any ideas as to what I am doing wrong. thanks

My answer is based on simplifying my approach some. Now I am simply using the default sequences supplied by postgress. So for instance now I have:
#Entity
#Table(name = "TBL_CACL")
public class Cacl {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Integer id;
#Column(name="NAME")
private String name;
// more stuff below...
, then in the repository (after querying postgress to get default sequences) I have:
#Query(value = "select last_value from tbl_cacl_id_seq", nativeQuery = true)
public Integer getCurrentVal();
And then:
int nextval = caclRepository.getCurrentVal();
works fine.

you could try removing the native query
#Query(value = "SELECT nextval('caclSeq')", nativeQuery =
true)
Long getNextSeriesId();

Related

How to update column in JPA native query which annothed with #Lob

I have an entity class and repository. Here I'm trying to execute update query but not working.
How to update Lob column in native query or any another solution on jpa query to update Lob column.
#Entity
#Table(name = "comment")
public class Comment implements Serializable {
#Basic
#Lob
#Column(name="Article_COMMENT", columnDefinition="TEXT")
private String articleComment;
#Basic
#Column(name = "ID_ARTICLE")
private Long articleId;
}
#Repository
public interface commentRepository extends JpaRepository<Comment, Long> {
#Query(value = "UPDATE comment set articleComment=: articleComment WHERE articleId =: articleId", nativeQuery=true)
void updateComment(#Param("articleComment") String articleComment, #Param("articleId") Long articleId );
}
Error:
No results were returned by query.
JpaSystemException thrown with message: could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet
Your question is very vague so I can answer on assumptions only. I think You want to update the articalComment field of your Entity. You can simply use .save() method of JpaRepository. Your code should be as follows. Here I am also assuming that your articleId is unique identifier to your entity class.
#Entity
#Table(name = "comment")
public class Comment implements Serializable {
#Basic
#Lob
#Column(name="Article_COMMENT", columnDefinition="TEXT")
private String articleComment;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID_ARTICLE")
private Long articleId;
}
Now your Id should be unique and has a #Id Annotation to identify it inside spring data JPA.
You don't have to add any code inside of your JPA repository. Simply call commentRepository.save(commentObject) method. If commentObject has an ID as 0 then a new Comment will be created. If the ID is a positive value and is present in your table that particular row will be updated not created.
remove the space try this way
UPDATE comment set articleComment=:articleComment WHERE articleId =:articleId

Spring Data Hibernate: N+1 problem and pagination

TL;DR -- I cannot find a way to solve the N+1 problem while doing pagination at the same time.
My Entities:
#Entity
public class Invoice {
#Id
#JsonView(InvoiceView.ShortView.class)
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
// other stuff
#OneToMany(targetEntity = InvoiceItem.class)
#JoinColumn(name = "invoice")
private List<InvoiceItem> items;
}
#Entity
public class InvoiceItem {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
// other stuff
}
My repository:
#EntityGraph(attributePaths = {"vendor","items"})
#Query(value = "select i from Invoice i where i.status=:status")
Page<Invoice> getInvoicesWithItemsByStatus(#Param("status") Status status, Pageable pageSpec);
or
#Query(value = "select i from Invoice i join fetch i.items join fetch i.vendor where i.status=:status",
countQuery = "select count(i) from Invoice i where i.status=:status")
Page<Invoice> getInvoicesWithItemsByStatus(#Param("status") Status status, Pageable pageSpec);
Both of these produce this Hibernate warning:
HHH000104: firstResult/maxResults specified with collection fetch; applying in memory!
and they do just that: fetch everything and give back the page requested. Every time a new page is requested, naturally.
Your problem and how to solve it is described in this article by Vlad Mihalcea
https://vladmihalcea.com/fix-hibernate-hhh000104-entity-fetch-pagination-warning-message/
Basically, you would need to write a native query.

findBy not working with inherited properties

I have the following model and repository:
#Entity
#Table(name = "db_user", uniqueConstraints = { #UniqueConstraint(columnNames = "email") })
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_user")
#SequenceGenerator(name = "seq_user", sequenceName = "seq_user")
#Column(name = "id")
private Long id;
// ...
}
#Entity
#Table(name = "movie")
public class Movie extends AbstractItem {
// Id column inherited from AbstractItem
// ...
}
#Entity
#Table(name = "movie_user")
public class MovieOwnership extends AbstractOwnership {
#ManyToOne
private Movie movie;
// ...
}
#MappedSuperclass
public abstract class AbstractOwnership{
#Id
#SequenceGenerator(name = "seq_default", sequenceName = "seq_default")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_default")
#Column(name = "id")
private Long id;
#ManyToOne
private User owner;
// ...
}
public interface MovieOwnershipRepository extends QueryDslJpaRepository<MovieOwnership, Long> {
List<MovieOwnership> findByOwnerId(Long ownerId);
MovieOwnership findByOwnerIdAndMovie(Long ownerId, Movie movieId);
List<MovieOwnership> findByOwnerIdAndMovieIdIn(Long ownerId, Set<Long> movieIds);
}
I'm trying to use Spring's findBy requests to fetch MovieOwnerships by owner or movie, using the id field of both entities. I'm able to work directly with the owner's id, but using MovieId in my requests seems broken (I can use the whole Movie object though). In the code above, the first two findBy are fine but the last one throws this exception:
Caused by: java.lang.IllegalArgumentException: Unable to locate
Attribute with the the given name [movieId] on this ManagedType
[carrm.app.data.AbstractOwnership]
It compiles if I try with another property from Movie (like findByMovieTitle), but I can't make it work on the id.
Any idea how to solve this?
I tried the same with JpaRepository instead of QueryDslJpaRepository.
The SQL is generated correctly:
select movieowner0_.id as id1_1_, movieowner0_.owner_id as owner_id2_1_, movieowner0_.movie_id as movie_id3_1_
from movie_ownership movieowner0_
left outer join user user1_ on movieowner0_.owner_id=user1_.id
left outer join movie movie2_ on movieowner0_.movie_id=movie2_.id
where user1_.id=? and (movie2_.id in (?))
So it must be a QueryDslJpaRepository implementation bug.
I would suggest you use JpaRepository instead.

SequenceGenerator not using next value of databasesequence

I have a problem in my application. I have an Oracle database with a sequence on a table. When i view the sequence in the database it says that last_number is 33800. However, when I try inserting a new object from my application the generated id is not 33800, but rather a smaller number. My guess is that Hibernate or whatever just finds the next available number. It does happen that my application deletes rows in the table, thus causing holes in the id-sequence. So, eventually I will get an exception because an ID i am trying to insert has already been used.
How can I configure the application so that it is always the sequence's last number + 1 that is used? I thought that this was default behavior, as I cannot recall encountering this problem.
This is my entity:
#Entity
#SequenceGenerator(name = "SequenceIdGenerator", sequenceName = "MY_SEQ", allocationSize = 20)
#Table(name = "myEntity")
public class myEntity {
private Long id;
#Id
#Column(name = "id")
#GeneratedValue(generator = "SequenceIdGenerator")
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
}
you can let hibernate handle this by
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id", nullable = false)
private Long id;
you can read more about it here https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing
You are using ORACLE so for you GenerationType.SEQUENCE will work as GenerationType.IDENTITY is not supported by Oracle

EntityNotFoundException in Hibernate Many To One mapping however data exist

I'm getting an error
Caused by: javax.persistence.EntityNotFoundException: Unable to find tn.entities.AgenceBnq with id 01
when I get AgenceBnq through Employee
Employee class:
#Table(name = "EMPLOYEE")
#NamedQuery(name = "Employee.findById", query = "SELECT e FROM Employee e WHERE e.employeMat = ?1"),
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "EMPLOYEE_MAT", unique = true, nullable = false, length = 15)
private String employeeMat;
...
#ManyToOne
#JoinColumn(name = "AGENCE_COD")
private AgenceBnq agenceBnq;
}
#Entity
#Table(name="AGENCEBNQ")
public class AgenceBnq implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="AGENCE_COD", unique=true, nullable=false, length=10)
private String agenceCod;
...
//bi-directional many-to-one association to Employee
#OneToMany(mappedBy="agenceBnq")
private Set<Employee> employees;
}
I'm calling namedQuery Employee.findById in DAO to retrieve data and I have to get AgenceBnq from Employee but get this error while calling query.getResultList()
#NotFound( action = NotFoundAction.IGNORE) isn't useful for me because data exist in AGENCEBNQ table and I have to retrieve date through Employee.
Is this a bug in hibernate ? I'm using hibernate version 3.6.7.Final
Firstly, You dont need query for it, the EnityManger.find(Employee.class, YOUR_ID) will do the job.
Secondly dont use ? in your queries but names (e.employeMat = :id) as it is easier to debug and less error prones for complicated queries.
Finally, check your DB table if the AGENCE_COD column in Employee table really contains the valid ID for your entitity that crashes (and that it length matches the ID length of AgenceBnq). It should work, the typical reason why it doesnt will be that your Employe.AGENCE_COD has defualt value and when creatubg the new EMploye you add it only to the Agence but you did not set Agence in the Employ.

Resources