I am building a rest api on Jhipster that must return the billers details using a Category ID as the search parameter. The call to the categories endpoint is returning list of categories but the call to the billers endpoint using one of the category id is returning a null result .
public interface ApplicationUrl {
String BILLERS = "/category/{categoryid}";
}
This is the controller :
#RequestMapping(ApplicationUrl.BASE_CONTEXT_URL)
public class BillingGatewayController {
#Autowired
private BillingGatewayService billingGatewayService;
#GetMapping(ApplicationUrl.BILLERS)
public BillersServiceResponse getAllBillersByCatId(#PathVariable Long categoryId) {
BillersServiceResponse defaultServiceResponse = new BillersServiceResponse();
defaultServiceResponse.setMessage(Message.fail.name());
ResponseCode responseCode = ResponseCode.BILLER_NOT_AVAILABLE;
log.debug("REST request to get all billers");
List<BillerDto> billers = billingGatewayService.findBillers(categoryId);
if (CollectionUtils.size(billers) > 0) {
responseCode = ResponseCode.SUCCESSFUL;
defaultServiceResponse.setStatus(responseCode.getCode());
defaultServiceResponse.setMessage(Message.SUCCESSFUL.name());
defaultServiceResponse.setData(billers);
}
defaultServiceResponse.setStatus(responseCode.getCode());
return defaultServiceResponse;
}
}
This is the service classes :
public interface BillingGatewayService {
List<BillerDto> findBillers(Long id);
}
public interface BillersRepository extends JpaRepository<Billers, Long>, JpaSpecificationExecutor<Billers> {
}
#Service("billingGatewayService")
public class BillingGatewayServiceImpl implements BillingGatewayService {
#Autowired
private ExtBillersRepository billersRepository;
#Override
public List<BillerDto> findBillers(Long categoryId) {
BillerResponseDto billerResponseDto = new BillerResponseDto();
List<BillerDto> billers = billersRepository.findAllActiveBillers(categoryId);
billerResponseDto.setBillers(billers);
billerResponseDto.setCategoryId(String.valueOf(categoryId));
return billers;
}
}
import com.fms.payfuze.dto.BillerDto;
import com.fms.payfuze.repository.BillersRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ExtBillersRepository extends BillersRepository {
String ACTIVE_BILLERS = "select new com.fms.payfuze.dto.BillerDto(b.id, b.name) from Billers b inner join b.categories c where c.id=b.id order by b.name";
#Query(ACTIVE_BILLERS)
List<BillerDto> findAllActiveBillers(#Param("id") Long id);
}
This is the billerDTO :
public class BillerDto {
private String billerId;
private String nameOfBiller;
public BillerDto(Long id, String name) {
this.billerId = String.valueOf(id);
this.nameOfBiller = name;
}
public String getBillerId() {
return billerId;
}
public void setBillerId(String billerId) {
this.billerId = billerId;
}
public String getNameOfBiller() {
return nameOfBiller;
}
public void setNameOfBiller(String nameOfBiller) {
this.nameOfBiller = nameOfBiller;
}
}
and this is the Billers class:
#Entity
#Table(name = "billers")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Billers implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "active")
private Boolean active;
#Column(name = "date_created")
private Instant dateCreated;
#OneToOne
#JoinColumn(unique = true)
private BillersRouterConfig billersRouterConfig;
#OneToMany(mappedBy = "billers")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<TransactionDetails> billers = new HashSet<>();
#ManyToMany(mappedBy = "billers")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JsonIgnore
private Set<Categories> categories = new HashSet<>();
Getters and setters
I have been on it for days and been brain storming , I'll appreciate all inputs but constructive and reconstructive . Thanks
You're passing #Param("id") in your repository but you are not actually using that id in your SQL Query. Your where condition only has a join statement. You need to add AND c.id = :id after joining the table so you can mention which category you want to get by category id.
Also, it should be WHERE c.biller_id = b.id in your JOIN statement?
Try something like this
String ACTIVE_BILLERS =
"select new com.fms.payfuze.dto.BillerDto(b.id, b.name)
from Billers b inner join
b.categories c
where c.billers_id = b.id and c.billers_id = :id
order by b.name";
Related
maybe duplicate question but I couldn't fina a solution for my case which I think is pretty simple.
I have two tables like so :
And those are the related DTO Object :
First table
#Entity
#Table(name = "DA10003_REF_SIGNALEMENT")
public class RefSignalement {
#Id
#Column(name = "CD_SIGNALEMENT")
public String codeSignalement;
#Column(name = "LIBELLE")
public String libelle;
#Column(name = "CATEGORIE")
public String categorie;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "CD_SIGNALEMENT")
public List<RefMessage> refMessages;
}
Second table :
#Entity
#Table(name = "DA10004_REF_MESSAGE")
public class RefMessage {
#Id
#Column(name = "CD_SIGNALEMENT")
public String codeSignalement;
#Id
#Column(name = "DESTINATAIRE")
public String destinataires;
#Column(name = "MESSAGE")
public String message;
}
And the following query to get all the RefSignelement with the associated message :
List<RefSignalement> listRefSignalement = em.createQuery("SELECT p FROM RefSignalement p, RefMessage m", RefSignalement.class).getResultList();
Unfortunately it's returning an empty list, I have tried to change it with join fetch but nothing change.
Thank for the help
Remember that in JPQL you have to think in Objects, not relations. You want to fetch all 'RefSignalement' and eagerly fetch their 'refMessages' properties:
SELECT DISTINCT s FROM RefSignalement s JOIN FETCH s.refMessages
Here the "distinct" is only needed by JPA when assembling your resulting entities, but add unnecessary overhead to the SQL Query. If you have a Hibernate version >= 5.2.2 (I think), then there is a query hint you can use to avoid that:
List<RefSignalement> sigs = entityManager
.createQuery(
"select distinct s " +
"from RefSignalement s " +
"left join fetch s.refMessages ")
.setHint("hibernate.query.passDistinctThrough", false)
.getResultList();
Read more about it here.
a couple of things, RefMessage class is using composite primary key so i guess you need to use #IdClass or #EmbeddedId annotation. here I'm providing using
#IdClass
public class RefId implements Serializable {
private String codeSignalement;
private String destinataires;
// default constructor
public RefId() {
}
public RefId(String codeSignalement, String destinataires) {
this.codeSignalement = codeSignalement;
this.destinataires = destinataires;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RefId refId = (RefId) o;
return Objects.equals(codeSignalement, refId.codeSignalement) &&
Objects.equals(destinataires, refId.destinataires);
}
#Override
public int hashCode() {
return Objects.hash(codeSignalement, destinataires);
}
}
then you need to use like follows
#Entity
#Table(name = "DA10004_REF_MESSAGE")
#IdClass(RefId.class)
public class RefMessage {
#Id
#Column(name = "CD_SIGNALEMENT")
public String codeSignalement;
#Id
#Column(name = "DESTINATAIRE")
public String destinataires;
#Column(name = "MESSAGE")
public String message;
}
define your repository as follows:
public interface RefSignalementRepo extends
JpaRepository<RefSignalement, String> {
}
RefSignalement class defination as follows:
#Entity
#Table(name = "DA10003_REF_SIGNALEMENT")
public class RefSignalement {
#Id
#Column(name = "CD_SIGNALEMENT")
public String codeSignalement;
#Column(name = "LIBELLE")
public String libelle;
#Column(name = "CATEGORIE")
public String categorie;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
#JoinColumn(name = "CD_SIGNALEMENT")
public List<RefMessage> refMessages;
}
very example app
#SpringBootApplication
public class App {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(App.class, args);
RefSignalementRepo repo = context.getBean(RefSignalementRepo.class);
RefSignalement obj = new RefSignalement();
obj.codeSignalement = "1";
obj = repo.save(obj);
obj.refMessages = new ArrayList<>();
RefMessage message = new RefMessage();
message.codeSignalement = "1";
message.destinataires = "2";
message.message = "custom message";
obj.refMessages.add(message);
obj = repo.save(obj);
List<RefSignalement> objs = repo.findAll();
System.out.println(objs.get(0).refMessages.size());
EntityManager em = context.getBean(EntityManager.class);
List<RefSignalement> listRefSignalement = em.createQuery("SELECT p FROM RefSignalement p, RefMessage m", RefSignalement.class).getResultList();
System.out.println(listRefSignalement.get(0).refMessages.size());
}
}
When I am implementing the Criteria API join for my spring boot study, I tried joining 2 classes and fetching the result. But when I am implementing and running I am getting the following error,
Unable to locate appropriate constructor on class [com.spacestudy.model.Investigator]. Expected arguments are: com.spacestudy.model.Employee
[cause=org.hibernate.PropertyNotFoundException: no appropriate constructor in class: com.spacestudy.model.Investigator]
And my Employee.java class like the following,
#Entity
#Table(name="employee")
public class Employee implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY, generator = "employee_seq_generator")
#SequenceGenerator(name = "employee_seq_generator", sequenceName = "employee_seq",allocationSize=1)
#Column(name="nemp_id",columnDefinition="serial")
public Integer nEmpId;
#Column(name="semp_name")
public String sEmpName;
#Column(name="sdesignation")
public String sDesignation;
#Column(name="ninst_id")
public Integer nInstId;
#Column(name="ndept_id")
public Integer nDeptId;
#Column(name="sclient_emp_id")
public String sClientEmpId;
#Column(name="ntemp_emp_id")
public Integer nTempEmpId;
#Column(name="bis_paid")
public boolean bIsPaid=true;
#Column(name="sunpaid_comment")
public String sUnpaidComment;
#ManyToOne(optional=true)
#JoinColumn(name="ndept_id", insertable = false, updatable = false)
public Department department;
#OneToMany(cascade = CascadeType.ALL,mappedBy="nEmpId")
public Set<Investigator> employeeInvestigatorJoinMapping;
public Employee() {
}
public Employee(Integer nEmpId, String sEmpName, String sDesignation, Integer nInstId, Integer nDeptId,
String sClientEmpId, Integer nTempEmpId, boolean bIsPaid, String sUnpaidComment, Department department,
Set<Investigator> employeeInvestigatorJoinMapping) {
super();
this.nEmpId = nEmpId;
this.sEmpName = sEmpName;
this.sDesignation = sDesignation;
this.nInstId = nInstId;
this.nDeptId = nDeptId;
this.sClientEmpId = sClientEmpId;
this.nTempEmpId = nTempEmpId;
this.bIsPaid = bIsPaid;
this.sUnpaidComment = sUnpaidComment;
this.department = department;
this.employeeInvestigatorJoinMapping = employeeInvestigatorJoinMapping;
}
}
And my second class Investigator.java,
#Entity
#Table(name = "investigator")
#JsonInclude(JsonInclude.Include.NON_NULL) // avoiding null values
public class Investigator implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "investigator_seq_generator")
#SequenceGenerator(name = "investigator_seq_generator", sequenceName = "investigator_seq")
#Column(name="ninvestigator_id")
public Integer nInvestigatorId;
#Column(name="sinvestigator_name")
public String sInvestigatorName;
#Column(name="ninst_id")
public Integer nInstId;
#Column(name="stitle")
public String sTitle;
#Column(name="ntemp_investigator_id")
public Integer nTempInvestigatorId;
#ManyToOne(optional = false)
#JoinColumn(name="nemp_id",referencedColumnName="nemp_id")
public Employee nEmpId;
// Default Constructor.
public Investigator()
{
}
public Investigator(Integer nInvestigatorId, String sInvestigatorName, Integer nInstId, String sTitle,
Integer nTempInvestigatorId, Employee nEmpId) {
super();
this.nInvestigatorId = nInvestigatorId;
this.sInvestigatorName = sInvestigatorName;
this.nInstId = nInstId;
this.sTitle = sTitle;
this.nTempInvestigatorId = nTempInvestigatorId;
this.nEmpId = nEmpId;
}
}
And Implemented the Criteria API joining like the following,
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Investigator> cq = cb.createQuery(Investigator.class);
Root<Employee> rootInvestigator = cq.from(Employee.class);
Join<Employee ,Investigator> resultEmployeeMappingObj
= rootInvestigator.join("employeeInvestigatorJoinMapping");
cq.multiselect(rootInvestigator);
cq.where(cb.equal(resultEmployeeMappingObj.get("nEmpId"), 21638));
List<Investigator> results = em.createQuery(cq).getResultList();
return results;
Where did I go wrong?
Criteria API
You have a few mistakes in the Criteria API query.
The working one looks like this
#Transactional(readOnly = true)
public List<Investigator> findByEmployeeId(int employeeId) {
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Investigator> query = criteriaBuilder.createQuery(Investigator.class);
Root<Investigator> investigator = query.from(Investigator.class);
Join<Investigator, Employee> employees = investigator.join("nEmpId");
query.select(investigator)
.where(criteriaBuilder.equal(employees.get("nEmpId"), employeeId));
TypedQuery<Investigator> typedQuery = em.createQuery(query);
List<Investigator> investigators = typedQuery.getResultList();
log.debug("Investigators: {}", investigators);
return investigators;
}
Spring Data JPA
Also, if your application is based on Spring Framework after renaming a few fields you can use Spring Data JPA and do not write query at all.
Employee entity:
#Entity
#Table(name = "employee")
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY, generator = "employee_seq_generator")
#SequenceGenerator(name = "employee_seq_generator", sequenceName = "employee_seq", allocationSize = 1)
#Column(name = "nemp_id", columnDefinition = "serial")
public Integer id;
//...
#OneToMany(cascade = CascadeType.ALL, mappedBy = "employee")
public Set<Investigator> investigators = new HashSet<>();
//...
}
Investigator entity:
#Entity
#Table(name = "investigator")
#JsonInclude(JsonInclude.Include.NON_NULL) // avoiding null values
public class Investigator implements Serializable {
//...
#ManyToOne(optional = false)
#JoinColumn(name = "nemp_id", referencedColumnName = "nemp_id")
public Employee employee;
//...
}
Spring Data JPA repository interface:
public interface InvestigatorRepository extends JpaRepository<Investigator, Integer> {
List<Investigator> findByEmployeeId(int employeeId);
}
That's it. Now you can simply inject the repository and use it:
#Autowired
private InvestigatorRepository investigatorRepository;
public void testQuery() {
investigatorRepository.findByEmployeeId(employee.getId()));
}
The exception seems to me that Criteria likes to have an Investigator constructor that takes an Employee argument:
public Investigator(Employee nEmpId) {
super();
this.nEmpId = nEmpId;
}
I'm facing a difficulty in developing a server in Spring (+ Hibernate + JPA) for a project.
The structure of the server (the part of interest in this case) is composed of catalogs composed of products that can have some related feedbacks.
Here I share the 3 entities:
Catalog.java
#Entity
#Data
#Table(name = "catalog")
public class Catalog {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable = false, unique = true)
private String name;
private String description;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "catalog_user_id", nullable = false)
private User user;
#ManyToMany(cascade = {CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinTable(name = "catalog_product",
joinColumns = {#JoinColumn(name = "catalog_id")},
inverseJoinColumns = {#JoinColumn(name = "product_id")}
)
private List<Product> products;
public Catalog() {}
}
Product.java
#Entity
#Data
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable = false, unique = true)
private String name;
private String description;
#Column(nullable = false, length = 1)
#MapKeyEnumerated(EnumType.ORDINAL)
private Category category;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "product_user_id", nullable = false)
private User user;
public Product() {}
}
Feedback.java
#Entity
#Data
#Table(name = "feedback")
public class Feedback {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "feedback_user_id", nullable = false)
private User user;
#Column(nullable = false, length = 1)
#MapKeyEnumerated(EnumType.ORDINAL)
private Rating rating;
private String text;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "product_id", nullable = false)
private Product product;
public Feedback() {}
}
The problem occurs when I try to delete some entities. What I want is:
when I delete a catalog also the catalog references in the "catalog_product" join table should be deleted (but the product linked with the catalog should not be deleted);
when I delete a product also the product references in the "catalog_product" join table and the feedbacks related to that product should be deleted;
when I delete a feedback nothing happens.
In the business layer I have this operations:
CatalogServiceImpl.java
#Service
public class CatalogServiceImpl implements CatalogService {
#Autowired
private CatalogDAO catalogDAO;
#Autowired
private ModelMapper mapper;
public CatalogDTO findById(Long id) {
Catalog catalog = catalogDAO.findById(id);
return mapper.map(catalog, CatalogDTO.class);
}
public CatalogDTO findByName(String name) {
Catalog catalog = catalogDAO.findByName(name);
return mapper.map(catalog, CatalogDTO.class);
}
public List<CatalogDTO> findByUserId(Long id) {
List<Catalog> catalogs = catalogDAO.findByUserId(id);
Type listCatalogsType = new TypeToken<List<CatalogDTO>>() {}.getType();
return mapper.map(catalogs, listCatalogsType);
}
public List<CatalogDTO> findAll() {
List<Catalog> catalogs = catalogDAO.findAll();
Type listCatalogsType = new TypeToken<List<CatalogDTO>>() {}.getType();
return mapper.map(catalogs, listCatalogsType);
}
public CatalogDTO createCatalog(CatalogDTO catalogDTO) {
Catalog catalog = mapper.map(catalogDTO, Catalog.class);
Catalog catalogFromDB = catalogDAO.save(catalog);
return mapper.map(catalogFromDB, CatalogDTO.class);
}
public CatalogDTO updateCatalog(CatalogDTO catalogDTO) {
Catalog catalog = mapper.map(catalogDTO, Catalog.class);
Catalog catalogFromDB;
if(catalogDAO.exists(catalog.getId())) {
catalogFromDB = catalogDAO.save(catalog);
} else {
catalogFromDB = null;
}
return mapper.map(catalogFromDB, CatalogDTO.class);
}
public void deleteCatalog(Long id) {
Catalog catalog = catalogDAO.findById(id);
if(catalog != null) {
catalogDAO.delete(catalog.getId());
}
}
}
ProductServiceImpl.java
#Service
public class ProductServiceImpl implements ProductService {
#Autowired
private ProductDAO productDAO;
#Autowired
private ModelMapper mapper;
public ProductDTO findById(Long id) {
Product product = productDAO.findById(id);
return mapper.map(product, ProductDTO.class);
}
public ProductDTO findByName(String name) {
Product product = productDAO.findByName(name);
return mapper.map(product, ProductDTO.class);
}
public ProductDTO findByCategory(Category category) {
Product product = productDAO.findByCategory(category);
return mapper.map(product, ProductDTO.class);
}
public List<ProductDTO> findByUserId(Long id) {
List<Product> products = productDAO.findByUserId(id);
Type listProductsType = new TypeToken<List<ProductDTO>>() {}.getType();
return mapper.map(products, listProductsType);
}
public List<ProductDTO> findAll() {
List<Product> products = productDAO.findAll();
Type listProductsType = new TypeToken<List<ProductDTO>>() {}.getType();
return mapper.map(products, listProductsType);
}
public ProductDTO createProduct(ProductDTO productDTO) {
Product product = mapper.map(productDTO, Product.class);
Product productFromDB = productDAO.save(product);
return mapper.map(productFromDB, ProductDTO.class);
}
public ProductDTO updateProduct(ProductDTO productDTO) {
Product product = mapper.map(productDTO, Product.class);
Product productFromDB;
if(productDAO.exists(product.getId())) {
System.out.println(product.toString());
productFromDB = productDAO.save(product);
} else {
productFromDB = null;
}
return mapper.map(productFromDB, ProductDTO.class);
}
public void deleteProduct(Long id) {
Product product = productDAO.findById(id);
if(product != null) {
productDAO.delete(product.getId());
}
}
}
Now, when I try performing the operations of deletion of catalog or product an error of constraint key fail is triggered. For example trying to delete a product which has a reference in the catalog_product join table:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`e01`.`catalog_product`, CONSTRAINT `FKdx5j7bcx77t7h0hjw6tvoxmp1` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`))
I don't understand if there's a way to set the relations between entities to make what I want in an automatic way with Spring, or if I have to remove records with reference manually before the deletion of the catalog/product.
Thanks a lot in advance to everyone!
Luca
i am trying to create a bidirectional one to many relationship.
#Entity
#XmlRootElement
#NamedQueries({
#NamedQuery(name = Company.FIND_ALL, query = "select c from Company
})
public class Company {
public static final String FIND_ALL = "Company.findAll";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String email;
private String name;
private String phoneNumber;
#OneToMany(mappedBy = "company")
private List<Place> places;
private long millisSince1970;
private boolean deleted;
public Company() {
}
#PrePersist
public void addMillisPrePersist() {
millisSince1970 = Instant.now().getEpochSecond();
deleted = false;
}
#PreUpdate
public void addMillisPreUpdate() {
millisSince1970 = Instant.now().getEpochSecond();
}
}
Place class:
#Entity
#XmlRootElement
#NamedQueries({
#NamedQuery(name = Place.FIND_ALL, query = "select p from Place p")
})
public class Place {
public static final String FIND_ALL = "Place.findAll";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private Type type;
private String email;
private String name;
private String city;
private String address;
private String phoneNumber;
private String latitude;
private String longitude;
private String workingHours;
#ManyToOne
#JoinColumn(name = "company_id", referencedColumnName = "id", nullable = false)
private Company company;
#OneToMany(mappedBy = "place")
private List<SpecialOffer> specialOffers;
#OneToMany(mappedBy = "place")
private List<Event> events;
private long millisSince1970;
private boolean deleted;
public Place() {
}
#PrePersist
public void addMillisPrePersist() {
millisSince1970 = Instant.now().getEpochSecond();
deleted = false;
}
#PreUpdate
public void addMillisPreUpdate() {
millisSince1970 = Instant.now().getEpochSecond();
}
}
And here is simple resource:
#GET
#Path("{companyId}")
#Produces({MediaType.APPLICATION_JSON})
public Company getCompany(#PathParam("companyId") int id) {
return entityManager.find(Company.class, id);
}
In my database i have Company and Place tables, in the Place table i have a foreign key column named company_id, so when i try to get some Company which has some corresponding Place glassfish returns http status 500 internal server error without any exception, and server logs are empty, thus i can not debug or understand the cause of this problem. If i try to get the company which doesn't have any places it returns it without any problem. So what am i doing wrong?
P.S. i think my question is similar to this one Glassfish: HTTP 500 Internal Server Error without any exception which unfortunately doesn't have any responses
I have a category table.In which first 5 are main category and
others are sub category.
I need to fetch the sub categories of first 5 main category so i have found the sql query
SELECT m.category_id,m.category_name AS 'Parent',
e.category_name AS 'Sub'
FROM category e
INNER JOIN category m ON m.category_id = e.parent_category_id
ORDER BY Parent
The query is joining the same table itself.and am getting the result given below
Result
How can i convert the SQL query to HQL and return the data like above image to user in
standard json format ?
FetchSubCategory
import java.io.Serializable;
import java.util.Set;
import javax.persistence.*;
#Entity
#Table(name = "category")
public class FetchSubCategory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "category_id")
private Integer categoryId;
#Column(name = "category_name")
private String categoryName;
#ManyToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "parent_category_id")
private FetchSubCategory parent;
#OneToMany(mappedBy = "parent")
private Set<FetchSubCategory> subCategory;
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public FetchSubCategory getParent() {
return parent;
}
public void setParent(FetchSubCategory parent) {
this.parent = parent;
}
public Set<FetchSubCategory> getSubCategory() {
return subCategory;
}
public void setSubCategory(Set<FetchSubCategory> subCategory) {
this.subCategory = subCategory;
}
}
Method
public Set<FetchSubCategory> fetchSubCategory() throws SQLException, ClassNotFoundException, IOException {
Set<FetchSubCategory> groupList = null;
try {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("SELECT m.categoryName AS 'Parent', e.categoryName AS 'Sub' FROM FetchSubCategory e INNER JOIN FetchSubCategory m ORDER BY Parent");
groupList = (Set<FetchSubCategory>) query.list();
} catch (Exception e) {
e.printStackTrace();
}
return groupList;
}
Can any one please correct my mistake and tell me how to fetch result like above image?
This stuff will solve your problem
#Entity
#Table(name = "category")
public class FetchSubCategory implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "category_id")
private Integer categoryId;
#Column(name = "category_name")
private String categoryName;
#NotFound(action = NotFoundAction.IGNORE)
#ManyToOne
#JsonIgnore
#JoinColumn(name = "parent_category_id")
private FetchSubCategory mainCategory;
#JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)//Avoiding empty json arrays.objects
#OneToMany(mappedBy = "mainCategory", fetch = FetchType.EAGER)
private List<FetchSubCategory> subCategory;
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public FetchSubCategory getMainCategory() {
return mainCategory;
}
public void setMainCategory(FetchSubCategory mainCategory) {
this.mainCategory = mainCategory;
}
public List<FetchSubCategory> getSubCategory() {
return subCategory;
}
public void setSubCategory(List<FetchSubCategory> subCategory) {
this.subCategory = subCategory;
}
Get your sub categories
public List<FetchSubCategory> fetchSubCategory() throws SQLException, ClassNotFoundException, IOException {
List<FetchSubCategory> groupList = null;
try {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("select distinct e FROM FetchSubCategory e INNER JOIN e.subCategory m ORDER BY m.mainCategory");
groupList = query.list();
} catch (Exception e) {
e.printStackTrace();
}
return groupList;
}
For self join as in your case, below will work for you.
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name = "parent_category_id")
private FetchSubCategory parent;
#OneToMany(mappedBy = "parent")
private Set<FetchSubCategory> subCategory;
FetchSubCategory entity class, we defined two attributes: FetchSubCategory parent and Set<FetchSubCategory> subCategory. Attribute parent is mapped with #ManyToOne annotation and subordinates is mapped with #OneToMany. Also within #OneToMany attribute we defined mappedBy="parent" making parent as the relationship owner and thus which manages the foreign relationship within table.
Also the annotation #JoinColumn is defined on parent making it the relationship owner. #JoinColumn defines the joining column which in our case is parent_category_id.