Stored Procedure Join Entities Hibernate/Spring Data - java

I got those two tables:
table z_users:
id
name
table z_phones:
id
iduser
phone
I got a stored procedure with this query too:
Select * from z_users INNER JOIN z_phones on z_users.id = z_phones.iduser where z_users.id = 1;
I would like to fetch this stored proc via Spring Data/Hibernate.
So i created two classes:
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Immutable;
import javax.persistence.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
#Data
#Entity
#Immutable
#NoArgsConstructor
public class ZUser {
#Id
private int id;
private String name;
public ZUser(String name, ZPhone... zPhones) {
this.name = name;
this.zPhone.addAll(Arrays.stream(zPhones).collect(Collectors.toUnmodifiableList()));
}
#OneToMany
private List<ZPhone> zPhone;
}
import lombok.Data;
import org.hibernate.annotations.Immutable;
import javax.persistence.Entity;
import javax.persistence.Id;
#Data
#Entity
#Immutable
public class ZPhone {
#Id
private int id;
private String phone;
}
I tried to call the SP with this code:
import lombok.extern.slf4j.Slf4j;
import net.resourcestorage.demojoin.database.model.ZUser;
import org.hibernate.Session;
import org.springframework.stereotype.Service;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.List;
#Slf4j
#Service
public class ZUserService {
#PersistenceContext
private EntityManager entityManager;
public List<ZUser> getUsers() {
Session session = (Session) entityManager.getDelegate();
Query query = session.createSQLQuery("CALL getUsers()").addEntity(ZUser.class);
log.info(query.getResultList().toString());
List list = query.getResultList();
return null; // don't care about this
}
}
Running this, Hibernate does this:
Hibernate: CALL getUsers()
Hibernate: select zphone0_.ZUser_id as zuser_id1_4_0_, zphone0_.zPhone_id as zphone_i2_4_0_, zphone1_.id as id1_2_1_, zphone1_.phone as phone2_2_1_ from ZUser_ZPhone zphone0_ inner join ZPhone zphone1_ on zphone0_.zPhone_id=zphone1_.id where zphone0_.ZUser_id=?
Here, hibernate should not do the select.
I start to think that I'm not following the best way, which could be the best way to achieve my goal?
Thanks!

Related

JPA Spring repository findAll() returns an empty List

I am trying to fetch all the records using JPA findAll. If I run the same query in the terminal, I get some rows as a result, but not through JPA. I tried other answers on stackoverflow, but nothing worked. I tried adding public getters and setters, although which I assume was done by the annotations.
Model class:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#Data
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#ToString
#Entity
#Table(name = "tea")
public class Product {
#Id
#GeneratedValue(generator = "prod_seq", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "prod_seq", sequenceName = "seq_prod", allocationSize = 1, initialValue = 1)
#Column(name = "product_id")
private int productId;
private String name;
#Column(name = "price_per_kg")
private int pricePerKg;
private String type;
#Lob
#Column(length = 2000)
private String description;
#Column(name = "image_url")
private String imageUrl;
private String category;
}
Service class:
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.tea.exceptions.ProductNotFoundException;
import com.tea.models.Product;
import com.tea.repository.ProductRepository;
#Service
public class ProductServiceImpl implements ProductService{
#Autowired
ProductRepository productRepository;
#Override
public List<Product> getAll() throws ProductNotFoundException {
return productRepository.findAll();
}
}
Edit: Adding the repository code:
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import com.tea.models.Product;
public interface ProductRepository extends JpaRepository<Product,Integer >{
#Query("from Product where type like :type ")
List<Product> findByType( String type);
#Query("from Product where type =?2 and category= ?1")
List<Product> findByCategoryAndType(String category, String type);
#Query("from Product where category like :category")
List<Product> findByCategory(String category);
}
I think query should contain alias name for table like Product p and then condition like p.type.

Mongodb and springboot how do I run specific queries

My account.java model is just this
package com.example.demo.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
#Getter
#Setter
#ToString
#Document(collection="Account")
public class Account {
#Id
private String id;
private String username;
private String password;
private String role;
}
here is my repo
package com.example.demo.repository;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import com.example.demo.model.Account;
public interface AccountRepository extends MongoRepository<Account, Integer> {
#Query("update Account u set u.username = ?1 where u.username = ?2")
void changeUsername(String firstname, String currentName);
}
This causes the error
Caused by: com.mongodb.util.JSONParseException:
update User u set u.username = "_param_1" where u.username = "_param_2"
I'm trying to this strictly using query but how? Is there a way to use mysql query style with mongodb because thats all i'm familiar with currently. If not. How would I do this with a mongodb query?

On Spring, how to query DynamoDB table using JPA and a composite key (Partition Key and Sort Key)?

I have a Spring project set up with JPA and Spring Data DynamoDB. It works alright. I can obtain items from the DynamoDB table by reading it by Partition Key and the Sort key (referred as DynamoDBHashKey and DynamoDBRangeKey).
My problem is that the way my repository is set up, the table is being read using query and scan operations, instead of get-item operation, which should be more efficient.
This is my entity:
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.annotation.Id;
#Getter
#Setter
#Builder
#NoArgsConstructor
#AllArgsConstructor
#DynamoDBTable(tableName = "my-entity-table")
public class MyEntity {
#Id
#DynamoDBHashKey
#DynamoDBAttribute(attributeName = "partition_key")
private String partitionKey;
#Id
#DynamoDBRangeKey
#DynamoDBAttribute(attributeName = "sort_key")
private String sortKey;
...
}
And this is my repository:
import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#EnableScan
#Repository
public interface MyEntityRepository extends CrudRepository<MyEntity, String> {
List<MyEntity> findByPartitionKeyAndSortKey(String partitionKey, String sortKey);
}
How do I configure my entity and repository to read items from the table using the get-item operation when my table has both a Partition Key and Sort Key?
Having done some research I stumbled onto this two articles:
Composite Primary Keys Kotlin Example
Spring Data JPA with a Hash & Range Key DynamoDB Table
The first one explains how to do what I want in Kotlin. Not bad, but it is not exactly what I'm looking for.
The second one hits the target perfectly, basically what it says is that I need to create a Primary Key object for my entity object, like this:
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBDocument;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIgnore;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.annotation.Id;
#Getter
#Setter
#Builder
#NoArgsConstructor
#AllArgsConstructor
#DynamoDBTable(tableName = "my-entity-table")
public class MyEntity {
#Id
#DynamoDBIgnore
private PrimaryKey primaryKey;
...
#DynamoDBHashKey
#DynamoDBAttribute(attributeName = "partition_key")
public String getPartitionKey() {
return primaryKey != null ? primaryKey.getPartitionKey() : null;
}
public void setPartitionKey(final String partitionKey) {
if (primaryKey == null) {
primaryKey = new PrimaryKey();
}
primaryKey.setPartitionKey(partitionKey);
}
#DynamoDBRangeKey
#DynamoDBAttribute(attributeName = "sort_key")
public String getSortKey() {
return primaryKey != null ? primaryKey.getSortKey() : null;
}
public void setSortKey(final String sortKey) {
if (primaryKey == null) {
primaryKey = new PrimaryKey();
}
primaryKey.setSortKey(sortKey);
}
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#DynamoDBDocument
public static class PrimaryKey {
#DynamoDBHashKey
#DynamoDBAttribute(attributeName = "partition_key")
private String partitionKey;
#DynamoDBRangeKey
#DynamoDBAttribute(attributeName = "sort_key")
private String sortKey;
}
}
Then, I don't need to create any custom query methods on my repository class:
#EnableScan
#Repository
public interface MyEntityRepository extends
CrudRepository<MyEntity, MyEntity.PrimaryKey> {
}
And after that, it is just matter of using JPA's CrudRepository methods to obtain the items, like this:
final MyEntity.PrimaryKey myEntityPK
= new MyEntity.PrimaryKey("partitionKey", "sortKey");
final MyEntity myEntity = myEntityRepository.findById(myEntityPK)
.orElseThrow(() -> ... );
To verify that it actually is using the get-item operation instead of the scan and query operations, one could place a couple of breakpoints on the following classes (as of spring-data-dynamodb-5.1.0):
org.socialsignin.spring.data.dynamodb.core.DynamoDBTemplate
org.socialsignin.spring.data.dynamodb.repository.support.SimpleDynamoDBCrudRepository

JSON return nested arrays instead of objects [Spring boot + JPA + MySQL + REST]

ISSUE
Hello Guys please help me to solve this.
I ve started building a REST API and got a problem when testing the URLs that I've made. Example: when I send request to get the list of one object, the request work fine but the data syntax returned by JSON is ugly: I got in result nested arrays instead of one global array containing json Objects inside it. Check my code please, I have 2 entities now that one of them depend on the other, I used #OneToMany to make relationships between them and no error has occured. Thanks in advance.
SOLUTION
The problem is: my query was returning a list of lists by default, so I had to modify my query by adding a constructor call. check this links please: using new keyword in HQL query
Also I added #JsonIgnore annotation to ignore some properties in my entities to prevent their show. Now the data is shown as formatted as I want :D thanks for your help. Check the new result here
Update
Hello again, I realized recently, that is bad to use #JsonIgnore annotation to prevent some properties from being send in the Json response, and the best way to customize which properties to send is to use DTOs class. Thanks again kj007
Entity 1
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import lombok.Data;
#Data
#Table(name = "x_assureurs") // this is the table name in DB
#Entity(name = "Assureurs") // This tells Hibernate to make a table out of this class
public class Assureurs {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "n_assureur")
private String id;
#Column(name = "nom_assureur")
private String name;
#OneToMany(mappedBy="assureur",fetch = FetchType.LAZY)
private List<Contrats> contrats;
}
Entity 2
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import lombok.Data;
#Data
#Table(name = "contrats") // this is the table name in DB
#Entity(name = "Contrats") // This tells Hibernate to make a table out of this class
public class Contrats {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "num_contrat")
private String num;
#Column(name = "nom_police")
private String nomPolice;
#ManyToOne
#JoinColumn(name = "courtier")
private Courtiers courtier;
#ManyToOne
#JoinColumn(name = "assureur")
private Assureurs assureur;
}
Repository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import tn.igase.gestdoc.models.entities.Assureurs;
// This will be AUTO IMPLEMENTED by Spring into a Bean called assureurRepository
#Repository
public interface AssureurRepository extends JpaRepository<Assureurs, String> {
// CONSTANTS
String FIND_ALL_BY_CONTRATS = "SELECT DISTINCT(contrat.assureur.id) as n_assureur, assureur.name \n"
+ " FROM Contrats contrat \n" + " JOIN Assureurs assureur ON contrat.assureur.id = assureur.id ";
String BY_ONE_COURTIER = "WHERE contrat.courtier.id = :idCourtier";
// QUERIES
#Query(FIND_ALL_BY_CONTRATS)
Iterable<Assureurs> findAllByContrats();
#Query(FIND_ALL_BY_CONTRATS + BY_ONE_COURTIER)
Iterable<Object> findAllByContratsAndCourtier(#Param("idCourtier") int idCourtier);
}
Service
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tn.igase.gestdoc.daos.AssureurRepository;
import tn.igase.gestdoc.models.entities.Assureurs;
#Service
public class AssureurService {
#Autowired
AssureurRepository assureurRepository;
public Iterable<Assureurs> findAllByContrats() {
return assureurRepository.findAllByContrats();
}
}
Controller
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import tn.igase.gestdoc.models.entities.Assureurs;
import tn.igase.gestdoc.service.AssureurService;
import tn.igase.gestdoc.service.ContratService;
/**
*
* Assureur controller
*
* #author fre
*/
#RestController
#RequestMapping(path = "/api/assureurs")
public class AssureurController extends MainController {
#Autowired
private AssureurService assureurService;
/**
* Revert all assureurs that all have contrats
*
* #return list
*/
#RequestMapping(path = "/all", produces=MediaType.APPLICATION_JSON_VALUE)
public Iterable<Assureurs> getAll() {
// This returns a JSON or XML with the users
Iterable<Assureurs> assureurs = new ArrayList<>();
assureurs = assureurService.findAllByContrats();
return assureurs;
}
}
Result
Check the JSON data returned here
Your current HQL will return list of objects that’s why you are seeing result like this.
you can either return entity or ID(type) from a HQL or JPA named query..not projected/custom columns.
To order to achieve your list of object you can do it via couple of ways..
As HQL will retrun list of objects you can parse the object according to your need in your service class method.
#Query(FIND_ALL_BY_CONTRATS)
List<Object> findAllByContrats();
2. Use DTO (Which is best way to it)
STEP1: Create DTO for projected columns you want, make sure constructure meet the parameters required from hql ..for example..
#Data
public class AssureursDTO {
private Long n_assureur;
private String name;
public AssureursDTO(Long n_assureur, String name) {
this.n_assureur = n_assureur;
this.name = name;
}
}
STEP 2: define your HQL like this by passing full package path of DTO, use yours
String FIND_ALL_BY_CONTRATS = "SELECT DISTINCT new com.example.demomysql21.entity.AssureursDTO(assureur.id as n_assureur, assureur.name) \n"
+ " FROM Contrats contrat \n" + " JOIN Assureurs assureur ON contrat.assureur.id = assureur.id";
STEP 3: Now it will return you LIST
#Query(FIND_ALL_BY_CONTRATS)
List<AssureursDTO> findAllByContrats();

Get OrderBy a ManyToOne relation In Hibernate

I Have 2 tables
1.User
2.Company
For each user there is a company. For each company it can multiple users.
UserBean.java
import java.io.Serializable;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
#Entity
#Table(name = "tab_user")
public class UserBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "user_id")
private int user_id;
#Column(name="user_login_pwd")
private String user_login_pwd;
#ManyToOne
#JoinColumn(name="comp_id")
private CompanyBean companyBean
And my CompanyBean is
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
#Entity
#Table(name = "tab_company")
public class CompanyBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "comp_id")
private Integer comp_id;
#Column(name = "comp_code")
private String comp_code;
#OneToMany(mappedBy = "companyBean" , fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(value = FetchMode.SUBSELECT)
private List<UserBean> companyUserList;
This is my CompanyBean mapping class.
Now i need to show list of users order by 'comp_code'. My DAO implementation for users list is
#SuppressWarnings("unchecked")
#Override
public List<UserBean> getUserList( String orderBy, String orderField) throws Exception{
List<UserBean> userList = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try{
Criteria crit = session.createCriteria(UserBean.class);
if(orderBy.equals("asc")){
crit.addOrder(Order.asc(orderField));
}else{
crit.addOrder(Order.desc(orderField));
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
userList = crit.list();
}finally{
session.close();
}
return userList;
}
So how can i get order by comp_code of CompanyBean in usersList? Please help.
No Hibernate solution is to create your own Comparator and to order with Collections.sort;
Hibernate solution is using of #OrderBy annotation.
Using hibernate with annotations, i want a one-many relationship to be sorted
By creating alias for beans we can get orderBy from manyToOne field
#SuppressWarnings("unchecked")
#Override
public List<UserBean> getUserList( String orderBy, String orderField) throws Exception{
List<UserBean> userList = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try{
Criteria crit = session.createCriteria(UserBean.class,"user").createAlias("user.companyBean", "company");
/*If my order field is from company bean then it should be company.company_field*/
if(orderBy.equals("asc")){
crit.addOrder(Order.asc(orderField));
}else{
crit.addOrder(Order.desc(orderField));
}
crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
userList = crit.list();
}finally{
session.close();
}
return userList;
}

Categories

Resources