How can I get a sequence number from an oracle database with jpaRepository? - oracle

I´m trying to get a sequence number from an oracle database using a jpaRepository.
The main problem is because I don´t have any Object in JpaRepository so I don´t really know how to solve it. The sequence number will be a Long, and I only need to return this number in my repository.
My code:
#Repository
public interface InsuranceRepository extends JpaRepository<Long, Long> {
#Query(value = "SELECT INSURANCE_VOUCHER_SEQ.nextval FROM dual", nativeQuery = true)
Long findInsuranceVoucher();
}
I know is wrong, but I don´t know how I should implement it.
Thanks everyone.

You could theoretically do it, but it will be ugly. How about using #PersistenceContext like so:
#Repository
public class InsuranceDao {
#PersistenceContext
private EntityManager entityManager;
public Long getInsuranceVoucher() {
Query q = entityManager.createNativeQuery("SELECT INSURANCE_VOUCHER_SEQ.nextval FROM dual");
return (Long) q.getSingleResult();
}
}

One workaround is to make a dummy entity that refers to the pseudo-table dual (I see the Oracle tag).
#Entity
public class Dual {
#Id
private String dummy;
/* ... boilerplate ... */
}
Then use this entity in your repository.

Related

Spring Data: can I create a method in the #Repository with a name what return list of object if String equals to constant?

Guess easier if I show you my example:
#Entity
class User {
Long id;
Status status;
}
enum Status {
NEW("N"), DELETED("D")
}
I have an AttributeConverter on Status so in DB the enum is stored with one character.
In my database I have entities like:
Table user
------------
Id Status
1 N
2 N
3 D
4 N
5 D
I want a method that list the Users with Status D. Something like this:
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByStatusEqualsD();
or
List<User> findByStatusEqualsDeleted();
problem is these are not working
}
I could write this:
List<User> findByStatus(Status status);
And call it as repo.findByStatus(Status.DELETED) but I want a method what returns only the deleted users.
If I call it as repo.findByStatus(Status.NEW) then it will return the new users.
I prefer to not write a #Query, I hope it is possible what I'm asking without doing it...
Thanks in advance.
Such behavior is not supported.
Method name is translated into JPQL expression (which is the same as used in #Query) with parameters in it (if needed) so you have to provide these. (https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation)
If you want query parameters to be hardcoded - #Query is what you need.
Alternatively you can have default method in your repository calling the parametrized one as mentioned here JpaRepository with Enum: findAllByOfferState_ACTIVE. NoSuchElementException
Easy,
You don't need a repo for that. Create a Service instead:
public interface UserDAOService{
List<User> getAllDeletedUsers();
}
And then just implement it with hardcoded findByStatus method from repo:
#Service
public class UserDAOServiceImpl implements UserDAOService{
private final UserRepository userRepository;
public UserDAOServiceImpl(UserRepository userRepository) {
this.userRepository= userRepository;
}
#Override
public List<Author> getAllDeletedUsers();
return userRepository.findByStatus(Status.DELETED);
}

Spring entity to DTO conversion

Suppose I have a class A like:
public class A{
Long aa;
}
And a Jpa Repository been extended on it. Now ARepo extends Jp...<A,Long>
Now I have have another DTO B like:
public class B{
Long bb;
Long cc;
}
I use this DTO once in a while, that's why I don't directly save it in DB.
Now what I'm doing is:
List<A>as=aRepo.getAll();
List<B>bs=new ArrayList<>();
for(A a:as)
bs.add(new B(a));
I don't like this and it seems real slow, how to resolve this ?
You might want to try JPQL NEW operator:
public interface ARepo extends JpaRepository<A, Long> {
#Query("SELECT NEW org.example.whatever.B(a) FROM A as a;")
List<B> findAllAsBs();
// all the other possible stuf...
}
You might need to adjust some aspects, but the principle.

Spring data JPA + Native query - replace query string depending on profile

I have service:
#Service
public class MessageServiceImpl implements MessageService {
private final MessageRepository smevMessageRepository;
private final Environment environment;
public MessageServiceImpl(MessageRepository messageRepository, Environment environment) {
this.messageRepository= messageRepository;
this.environment = environment;
}
#Override
public List<Message> findReadyToSend() {
if (environment.acceptsProfiles("postgre")) {
return messageRepository.findReadyToSendPostgre();
}
return messageRepository.findReadyToSendOracle();
}
And It is my repository:
#Repository
public interface MessageRepository extends JpaRepository<Message, String> {
#Query(value = "select sm.* from MESSAGES sm ...", nativeQuery = true)
List<Message> findReadyToSendOracle();
#Query(value = "select sm.* from MESSAGES sm ...", nativeQuery = true)
List<Message> findReadyToSendPostgre();
If I start spring boot server with oracle profile I call findReadyToSendOracle method and if postgre profile - findReadyToSendPostgre method. It work. But this solution is bad. I think. Because I write hardcode for profile check. and my repository has 2 methods for different DB.
How to implement this correctly?
What are the problems you are facing while adapting to JPQL? Using native/custom functions? It might look way too difficult, but you might find a way using criteria + the function function from JPA 2.1+, take a look at this article.
On the other hand, I found an old workaround of mine here that might help. There is a simple way to solve that using a few shortcuts with the #Profile annotation and some extra interfaces.
If you provide an interface with your expected native query method that extends JpaRepository, like this:
#NoRepositoryBean
public interface MessageRepository extends JpaRepository<Message, String>{
List<Message> findByReady();
}
Note the #NoRepositoryBean, avoiding duplicate beans with profile specialization.
Then, just provide your implementations according to your needs:
#Repository
#Profile("oracle")
public interface MessageOracleRepository extends MessageRepository {
#Query(value = "select m.* from Message m where m.ready = false", nativeQuery = true)
List<Message> findByReady();
}
... and ...
#Repository
#Profile("mysql")
public interface MessageMySQLRepository extends MessageRepository {
#Query(value = "select m.* from Message m where m.ready = true", nativeQuery = true)
List<Message> findByReady();
}
Now you will only need to provide the desired profile, inject and use the correct native queries.
As you can see I simplified the queries, for the sake of simplicity. Take a look at this repository with the adapted code.

Spring data query where column is null

Suppose I have entities (getters/setters and various details omitted for brevity):
#Entity
class Customer{
...
#OneToMany(cascade = CascadeType.ALL, mappedBy = "customer")
Collection<Coupon> coupons;
}
#Entity
class Coupon{
...
#Temporal(value = TemporalType.TIMESTAMP)
private Date usedOn;
#ManyToOne(fetch = FetchType.LAZY)
#NotNull
Customer customer;
}
I wish retrieve all Coupons for a given Customer having null usedOn.
I,'ve unsuccessfully defined a method in the CouponRepository as described in docs
#Repository
public interface CouponRepository extends CrudRepository<Coupon, Long> {
Collection<Coupon> findByCustomerAndUsedOnIsNull(Customer);
}
but this leads on a compiler error Syntax error, insert "... VariableDeclaratorId" to complete FormalParameterList.
My fault, the correct definition is
#Repository
public interface CouponRepository extends CrudRepository<Coupon, Long> {
Collection<Coupon> findByCustomerAndUsedOnIsNull(Customer customer);
}
I simply missed the parameter name :-(
You can use IsNull to check null columns in JPA query.
For example for any columnA you can write query like query like
findByColumnAIsNull
In this case you can write queries like
#Repository
public interface CouponRepository extends CrudRepository<Coupon, Long> {
Collection<Coupon> findByCustomerAndUsedOnIsNull(Customer customer);
List<Coupon> findByUsedOnIsNull();
}
Also you can check how this queries will be
Refer this Spring Data JPA Query creation this will help you lot to understand and create different type of JPA query variation.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
Try changing your method to this (assuming Customer.id is a long):
Collection<Coupon> findByCustomer_IdAndUsedOnIsNull(Long customerId);
then use like this:
repo.findByCustomer_IdAndUsedOnIsNull(customer.getId());

Proper Way to layer Spring JPA based DAO using Spring Boot Framework

Am new to Spring Boot & JPA...
Let's say I have two entities mapped to two tables which are joined in a database.
Student-1------<-Course
Also, lets presume that the database is already created and populated.
This depicts that one student has many courses...
My Student Entity:
#Entity
public class Student {
#OneToMany(mappedBy="student")
private List<Courses> courses;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Student_Id")
private long studentId;
#Column(name = "Student_Name")
private String studentName;
protected Student() { }
// Getters & Setters
}
My Course Entity:
#Entity
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Course_Id")
private long courseId;
#Id
#Column(name = "Student_Id")
private long studentId;
#ManyToOne
#PrimaryKeyJoinColumn(name="Student_Id", referencedColumnName="Student_Id")
private Student student;
#Column(name = "Course_Name")
private String courseName;
// Getters & Setters
}
In Spring Boot's Tutorial Guides, it illustrates how to extend a CrudRepository interface, but
it doesn't specify how to setup a Spring based DAO which contains custom finder methods which use HQL and EntityManager inside it.
Is the following DAO and DaoImpl correct?
public interface CourseDao {
List<Course> findCoursesByStudentName(String studentName);
}
#Repository
public class CourseDaoImpl implements CourseDao {
#PersistenceContext
EntityManager em;
public List<Course> findCoursesByStudentName(String studentName) {
String sql = "select c.courseName" +
"from Course c, Student s " +
"where c.course_id = s.student_id " +
"and s.studentName = :studentName ";
Query query = em.createQuery(sql);
query.setParameter("studentName", studentName);
return query.getResultList();
}
}
And then in the client code, for example, in the main class:
public class Application {
#Autowired
CustomerDao dao;
public static void main (String args []) {
List<Course> courses = dao.findCoursesByStudentName("John");
}
}
Is this the standard way to use HQL inside Spring DAOs ? I've seend examples of the #Transactional annotation being prepended to the DAO class's impl (e.g. CustomerDAOImpl) ?
Please let me know if this is the write way to structure my Spring Boot app or am I supposed to extend / add to the CrudRepository only?
If someone could correct my example and point me to a URL which talks about HQL using Entities that are joined, I would be very grateful.
The Spring Boot guides didn't depict joins or DAOs - I just need to learn how to properly create finder methods which emulate select statement which return lists or data structures.
Thanks for taking the time to read this...
If I understood your question correct you do have two questions:
How to create a DAO and DAOImpl?
Where to put your Transaction annotations?
In regards to the first question I want to point out that this is a question in regards to spring-data-jpa using Hibernate as a JPA provider, not spring-boot.
Using Spring Data I usually skip completely to create a DAO but directly use a Custom Repository extending a standard one like CrudRepository. So in your case you don't even have to write more code than:
#Repository
public interface StudentRepository extends CrudRepository<Student, Long> {
List<Student> findByStudentName(String studentName);
}
Which will be sufficient and Spring Data will take care of filling it with the correct implementation if you use
#Autowired
StudentRepository studentRepo;
in your service class. This is where I also usually annotate my methods with #Transactional to make sure that everything is working as expected.
In regards to your question about HQL please look into the spring data jpa documentation, which points out that for most of the cases it should be sufficient to stick to proper named methods in the interface or go for named queries (section 3.3.3) or use the #Query annotation (section 3.3.4) to manually define the query, e.g. should work (didn't tried):
#Repository
public interface #CourseRepository extends CrudRepository<Course, Long> {
#Query("select c.courseName from Course c, Student s where c.course_id = s.student_id and s.studentName = :studentName")
public List<Course> findCoursesByStudentName(String studentName);
}
If you annotate your CourseDaoImpl with #Transactional (Assuming your have defined JpaTransactionManager correctly) You can just retrieve the Student with the matching name and call the getCourses() method to lazy load the Courses attached to that student. Since findCoursesByStudentName will run within a Transaction it will load the courses just fine.
#Repository
#Transactional(readOnly=true)
public class CourseDaoImpl implements CourseDao {
#PersistenceContext
EntityManager em;
public List<Course> findCoursesByStudentName(String studentName) {
String sql = "select s " +
"from Student s " +
"where s.studentName = :studentName ";
Query query = em.createQuery(sql);
query.setParameter("studentName", studentName);
User user = query.getSingleResult();
if(user != null) {
return user.getCourses();
}
return new ArrayList<Course>();
}
}

Resources