Spring entity to DTO conversion - spring

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.

Related

mapping entity to DTO with nested DTO

I have a relationnal (heavy) database model with a lot of table dependencies and foreign keys.
We have choosen to use DTOs in order to simplify data representation ton front and hide database mode complixity.
But we have DTO with nested DTO. And we have Mapper implementation classes to set data with small business/functional logic.
The question is if it is a good pratice that a mapper class calls mapper (etc.) or is it a best way to have a main class handling all mapper classes ? (Example 1 or2)
Example 1 :
#Component
public class ActorMapperImpl implements ActorMapper {
#Autowired
private InsurerMapper insurerMapper;
#Autowired
private PersonMapper personMapper;
#Autowired
private CorrespondentMapper correspondentMapper;
....
#Override
public ActorDto mapToDto(Acteur actor) {
final ActorDto actorDto;
if (actor != null) {
....
actorDto.setPerson(personMapper.personneToPersonDto(actor.getPersonne()));
if (actor.getInsurer() != null) {
actorDto.setInsurer(insurerMapper.entityToDto(actor.getInsurer()));
} else if (actor.getCorrespondantAssureur() != null) {
actorDto.setInsurer(correspondentMapper.correspondentToInsurerDto(actor.getCorrespondantAssureur()));
}
....
// intermediate
final Intermediaire intermediate = actor.getIntermediaire();
if (intermediate != null) {
.....
if (person != null) {
intermediateDto = personMapper.personneToPersonDto(person);
intermediateDto.setQuality(quality);
}
.....
}
.....
Example 2 :
#Service
public class FinancialSlipOrchestratorImpl implements FinancialSlipOrchestrator {
.....
#Autowired
private FinancialSlipMapper financialSlipMapper;
#Autowired
private PersonMapper personMapper;
..... some public / private methods
private FinancialSlipDto fullMapToDto(FinancialSlip financialSlip) {
.....
// Financial slip
var financialSlipDto = financialSlipMapper.mapToDto(financialSlip);
// person
financialSlipDto.setIssuerPerson(personMapper.personneToPersonDto(financialSlip.getIssuerPerson()));
....
// RIB
financialSlipDto.setRib(ribMapper.mapToDto(financialSlip.getRib()));
return financialSlipDto;
}
I would say that it's ok for one mapper to call another and think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(Acteur.class)
public interface ActorDto {
#IdMapping
Long getId();
String getName();
PersonDto getPerson();
default InsurerDto getInsurer() {
return getMainInsurer() != null ? getMainInsurer(): getCorrespondantAssureur();
}
#Mapping("insurer")
InsurerDto getMainInsurer();
InsurerDto getCorrespondantAssureur();
IntermediaireDto getIntermediaire();
#EntityView(Person.class)
interface PersonDto {
#IdMapping
Long getId();
String getName();
}
#EntityView(Insurer.class)
interface InsurerDto {
#IdMapping
Long getId();
String getName();
}
#EntityView(Intermediaire.class)
interface IntermediaireDto {
#IdMapping
Long getId();
String getName();
Integer getQuality();
PersonDto getPerson();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
ActorDto a = entityViewManager.find(entityManager, ActorDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
The best thing about this is, it will only fetch the data that is actually necessary.
If you use DTOs for flushing back changes as well, you will be delighted to hear that Blaze-Persistence Entity-Views also supports that in a very efficient manner. This will allow you to get rid of all those manually written mappers :)

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

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.

Spring Data JPA - findBy mapped object

In my legacy application, I have a country table, state table and a mapping table for country and state with few additional columns.
I have created an entity class like this.
class CountryStateMapping {
#Id
private long id;
private Long countryId;
#OneToOne
#JoinColumn(name="state_id")
private State state;
//getters seters
}
My repository.
public interface CountryStateMapping extends JpaRepository<CountryStateMapping, Long>{
Optional<CountryStateMapping> findByStateId(long stateId);
Optional<CountryStateMapping> findByState(State state);
}
I would like to check if the state exists in the mapping table. Both of the below approaches do not work.
countryStateMapping.findByStateId(long stateId)
countryStateMapping.findByState(State state)
What is the right way?
Its not the correct way i feel.The correct way for doing this will be
public interface CountryStateMappingRepository extends JpaRepository<CountryStateMapping, Long> {
Optional<CountryStateMapping> findByStateId(long stateId);
#Query("select s.something from State s" )
Optional<CountryStateMapping> findByState(State state);
}
This implies two things
By extending JpaRepository we get a bunch of generic CRUD methods to create, update, delete, and find
2.It allows Spring to scan the classpath for this interface and create a Spring bean for it.
Also you need some configuration.For that you need to create a configuration class to be used with your data source.You can find many examples to do the same and one such is https://www.baeldung.com/the-persistence-layer-with-spring-data-jpa.
You can also use custom queries and simple queries using the #Query annotation.
Thanks
Try with an underscore for id like below;
public interface CountryStateMapping<CountryStateMapping, Long>{
Optional<CountryStateMapping> findByState_Id(long stateId);
Optional<CountryStateMapping> findByState(State state);
}

Spring Data JPA repository methods overloading

For example, I have a book JpaRepository. Book has a field called Name, the book repository has a method findOneByName (as the jpa repository method naming convention). But I need two different versions of findOneByName to use in different use cases. One version is lock annotated, the other is lock-free. Like this:
public interface BookRepository extends JpaRepository<BookDAO, Long> {
#Lock(LockModeType.READ)
BookDAO findOneByName( String name );
BookDAO findOneByName( String name );
}
Is it possible to achieve this in Spring? If so, how to distinguish the two methods when calling them. If not, is there another way to do it while still using the Spring JPA repository interfaces (like findOneBy***).
According to reference we can name query methods with these prefixes: find…By, read…By, query…By, count…By, and get…By.
So methods BookDAO findByName(String name) and BookDAO getByName(String name) will do the same thing.
I dont know if it can be done your way. But i would create different methods
public interface BookRepository extends JpaRepository<BookDAO, Long> {
#Lock(LockModeType.READ)
#Query("select b from Book b where b.name = :name")
BookDAO findOneByNameForRead( String name );
BookDAO findOneByName( String name );
}
or you can create methods in your service layer instead of using spring jparepository to handle locking. and use it across where it is needed to be updated, and all read methods marked as #Transactional(readOnly = true)
#PersistenceContext
private EntityManager em;
...
public Book findOneBookForUpdate(String id) {
Book book = em.find(Book.class, id);
if (book != null) {
em.lock(book, LockModeType.PESSIMISTIC_WRITE);
}
return book;
}

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