Mapping value from alias column into #Entity Class - spring

Is there any possible way to map value from alias column in query for my #Entity Class? For example, for this case there are new columns : first name and last name which is not exist in Transaction Table. Is there any way to map the value into Transaction #Entity Class?
Example entity and dao
#Entity
import java.sql.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="Transaction")
public class Transaction {
#Id
#Column(name="customer_id")
private String customerId;
#Column(name="first_name")
private String firstName;
#Column(name="last_name")
private String lastName;
#TransactionDAO
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
#Repository
public interface TransactionDao extends PagingAndSortingRepository<Transaction, Long>, QuerydslPredicateExecutor<Transaction>{
#Query(value = "SELECT customer_id, SUBSTR (customer_name, 1, 10) as first_name, SUBSTR (customer_name, 11, 20) as last_name FROM Transaction WHERE customer_id=:#{#customerId}", nativeQuery = true)
public List<Transaction> selectByTransaction(#Param("customerId") String customerId);
}
If i use #Column annotation for first_name and last_name, there will be an error because two of that column is not existing in Transaction Table

Yes it's possible to map output of a Query to different model. Answer here is Projection via Interface. You can create interface with field names you want to receive from Query or Repository method. For exaple if you want to receive only firstName and lastName you create Interface like this one below. Other fields will be omitted. Fields in Interface can be diffrent than fields in your #Entity class.
interface TransactionProjection {
String getFirstName();
String getLastName();
}
Helpful links:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections
https://www.baeldung.com/spring-data-jpa-projections

Related

How do I update a product that is partially defined then later add additional product details to it

I have a product that is partially defined when it is first created. It is assigned a product code and a category to which it belongs. Later when the marketing group provide details, these details need to be updated by adding the details to the product. These are done by different groups. A batch job obtains the product partial product details from one database and the product details from a relational database and then updates the product with the product details in a MongoDb database. Here is the objects as they exist initially. The Product details get assigned a product code and category and written to the MongoDB database. The batch job runs nightly checking for product details for the Product and then should update the Product with the ProductDetails when they become available in the relational database. Here are the objects:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Data
#NoArgsConstructor
#AllArgsConstructor
#Document
public class Product {
#Id
private long productCode;
private String category;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
#Data
#NoArgsConstructor
#AllArgsConstructor
public class ProductDetail {
private long productCode; // matches the product code in Product
private String description;
private int quantityOnHold;
private BigDecimal price;
private String warehouseLocationId;
private float discountFactor;
private String orderDescCode;
private String vendorId;
}
I am wondering what's the way to update the Product with the Product details. Do I create the equivalent Product document and add the Product details as a nested document? Is there a way to simply update the existing document by first modeling it as it is i.e. just the Product with its 2 fields and then add the ProductDetail? I'm relatively new to using Spring Data Mongo, so I don't know what the approach should be that makes the most sense, please help.
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Data
#NoArgsConstructor
#AllArgsConstructor
#Document(collection="product_collection")
public class Product {
#Id
private long productCode;
private String category;
private ProductDetail productDetail;
}
#Data
#NoArgsConstructor
#AllArgsConstructor
public class ProductDetail {
private String description;
private int quantityOnHold;
private BigDecimal price;
private String warehouseLocationId;
private float discountFactor;
private String orderDescCode;
private String vendorId;
}
You can use spring-data-mongodb to do that.
You can use the following methods to update documents.
save – Update the whole object, if “_id” is present, perform an update, else insert it. Notice that an "_id" field is generated by spring-data-mongo and mapped to the field annotated with #Id.
updateFirst – Updates the first document that matches the query.
updateMulti – Updates all documents that match the query.
Upserting – If no document that matches the query, a new document is created by combining the query and update object.
findAndModify – Same with updateMulti, but it has an extra option to return either the old or newly updated document.
The easiest way to find and update an document in my opinion is to use mongoRepository :
import com.globallogic.spring.mongodb.model.Book;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface ProductRepo
extends MongoRepository<Product, Long> {
}
And then inject your mongoRepository in a service class:
#Service
public interface ProductService {
ProductRepo productRepo;
//injecting productRepo into you service
public ProductService(ProductRepo productRepo) {
this.productRepo = productRepo;
}
public void updateproduct(Long productCode, ProductDetail productDetail ) {
Product pFromMongo = productRepo.findOne(productCode);
//set whatever you want on pFromMongo
pFromMongo.setDetail(productDetail);
....
//And then save the productCode. This will add or update product detail
productRepo.save(pFromMongo);
}
}
The resulting product in MongoDB will look like :
{
productCode : 1,
category: "pCateg",
productDetail : {
description : "description",
quantityOnHold : 11,
price : 12.33,
warehouseLocationId : "warehouseLocationId",
discountFactor : 1.0,
orderDescCode : "orderDescCode",
vendorId: "vendorId"
}
}
You can take a look at this presentation https://www.youtube.com/watch?v=ReqMU6bmPNM&ab_channel=JavaTechie

Unable to Map Data Type in Spring JPA using Projections

I am trying to Fetch Data from Posgresql DB using Projection Interface but Unable to Map UUID to the Projection correctly. I can always cast it as text or byte and then convert back to UUID but that isn't the most efficient approach for the whole project with multiple queries.
UserProjection.class
import java.util.UUID;
public interface UserProjection {
UUID getUserId();
}
UserTestRepo.class
import java.util.List;
import java.util.UUID;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
#Repository
public interface UserTestRepo extends JpaRepository<UserTest, UUID> {
#Query(nativeQuery = true, value = "select user_id as userId from user_test")
public List<UserProjection> getProjectionData();
}
UserTest.class
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Type;
#Table(name = "user_test")
#Entity
public class UserTest {
#Id
#Column(name = "user_id")
#Type(type = "uuid-char")
public UUID userId;
}
Execution Statements :
List<UserProjection> list = userRepo.getProjectionData();
System.out.println(list.get(0).getUserId());
PosgresSQL Structures is a simple UUID entry.
I am getting No Dialect mapping for JDBC type: 1111 error.
Your query: #Query(nativeQuery = true, value = "select user_id as userId from user_test") is returning a list of userId from user_test table, not a list of UserProjection. So, you can either declare a constructor and project your values there or just take return a list of userId in your query method.
Simply try this:
#Query(nativeQuery = true, value = "select user_id as userId from user_test")
public List<UUID> getProjectionData();
Or
#Query(nativeQuery = false, value = "select new full_dto_path.UserProjection(user_id) from UserTest")
public List<UserProjection> getProjectionData();
Before applying second approach, make sure you have defined your constructor for that single field.
Note: full_dto_path means the fully qualified path of your UserProjection dto.
Hope this will work.

Joining tables and returning data to react with Spring JPA

I am trying to join two entities in Spring JPA so that I can access the data in react.
I have an Event and Course entity with corresponding tables in postgres.
In react I loop through all the events in the database and display them on a card for each event. The Event table contains the courseid where that event is being played at. But I want to show on the card the coursename rather than the courseid.
I dont currently have access to this so need to join the tables so I have access to it.
I have never used queries in Spring JPA and struggling to create one to make this join.
I want something like this SQL query,
select * from event join course on course.courseid=event.course_id where eventid=5
where the eventid will be passed from react to Spring so that during each loop, it will get the correct eventid and display the corresponding coursename for that event.
Implementation:
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
#Entity
public class Course {
#Id
#Column(name = "courseid")
private Long id;
#Column(name = "coursename")
private String courseName;
#OneToMany(mappedBy = "course")
private List<Event> events;
// ...
}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
#Entity
public class Event {
#Id
#Column(name = "eventid")
private Long id;
#ManyToOne
#JoinColumn(name = "course_id")
private Course course;
// ...
}
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface EventRepository extends JpaRepository<Event, Long> {
}
Usage:
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MyController {
#Autowired
private EventRepository eventRepository;
#GetMapping
public Map<String, ? extends Object> index(#RequestParam("id") final long id) {
// find by eventid
final Optional<Event> res = eventRepository.findById(id);
res.ifPresent(e -> {
// course name
System.out.println(e.getCourse().getCourseName());
});
return res.map(e -> Map.of("id", e.getId(), "course", e.getCourse().getCourseName()))
.orElse(Map.of());
}
}

Nested property not found in a Spring Data query method declaration

I'm trying to use findBy... in my repository to get a Savingaccount object passing a nested attribute(name) as a parameter. Currently I'm using:
Mono<SavingAccount> findByOwnerName(String name);
but I'm getting this error: No property name found for type Owner! Traversed path: SavingAccount.owner.
My repository:
package com...SavingAccMS.Repository;
import com.everis.SavingAccMS.Model.Owner;
import com.everis.SavingAccMS.Model.SavingAccount;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import reactor.core.publisher.Mono;
public interface SavingAccountRepo extends ReactiveMongoRepository<SavingAccount, String>
{
Mono<SavingAccount> findByNumber(String number);
//This one is the problem
Mono<SavingAccount> findByOwnerName(String name);
Mono<SavingAccount> findByOwner(Owner owner);
}
My Entity:
package com...SavingAccMS.Model;
import java.security.acl.Owner;
import javax.validation.constraints.NotBlank;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Data;
#Data
#Document(collection = "SavingAccs")
public class SavingAccount
{
#Id
private String id;
#NotBlank
private String number;
#NotBlank
private Owner owner;
#NotBlank
private String currency;
#NotBlank
private double balance = 0.00;
#NotBlank
private String status;
}
package com...SavingAccMS.Model;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Data;
#Data
#Document(collection = "Owners")
public class Owner
{
public String dni;
public String name; //findBy this attribute is required.
}
According to your imports, the Owner in your SavingAccount refers to java.security.acl.Owner, not the one you defined yourself in om...SavingAccMS.Model.Owner. The former does not carry a name attribute.
I'm not certain but I don't think you can find the owner name in hibernate like that.
I would try the following!
#Query("SELECT * FROM SavingAccount where owner.name = :name")
Mono<SavingAccount> findByOwnerName(#Param("name") String name);

How to write query by using findBy..() methods for one record

I've an entity class User_Details
package vl.cybersecurityapplication.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "User_Details")
public class User_Details implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "UserId")
private int userId;
#Column(name = "FirstName")
private String firstName;
#Column(name = "LastName")
private String lastName;
#Column(name = "Password")
private String password;
#Column(name = "E_Mail")
private String eMail;
#Column(name = "Mobile_Num")
private int mobileNumber;
//getters and setters
}
Here is my repo interface
package vl.cybersecurityapplication.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import vl.cybersecurityapplication.model.User_Details;
public interface IUserRepository extends JpaRepository<User_Details, Long> {
public Integer findMobileNumberByName(String userName);
}
This is my repo class
package vl.cybersecurityapplication.repository;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import vl.cybersecurityapplication.model.User_Roles;
#Transactional
#Repository
public class UserRepository{
#Autowired
IUserRepository userRepository;
public Integer findMobileNumberByName(#PathVariable String lastName) {
int mobileNumber = userRepository.findMobileNumberByName("shaik");
System.out.println("Mobile Number : "+mobileNumber);
return mobileNumber;
}
}
I'm new to Spring Boot and JPA.
Here I need to query mobile number in User_Details table by using lastname.
i.e., Select Mobile_Num from User_Details where LastName= "xyz";
Can Some one help me how to wo write this query in my repo class.
You can write like this. But you cannot fetch only MobileNumber. You will get a complete object.
List<User> findByLastName(String lastname).
If you want to get only some fields then you should check out Projections
No need to use a native query. JPA supports object based query.
You can use List findByLastName(String lastname) which will generate that query in the backend and return the result.

Resources