How to map results of a Hibernate Query to a DTO object? - java

I have the following 3 Hibernate Entities within my Java Project:
CompanyStatus
#Entity(name = "company_status")
#Table(name = "company_status")
public class CompanyStatus implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#JsonProperty
#Column(name = "company_status_id")
private Integer companyStatusId;
#JsonProperty
#Column(name = "company_status_label")
private String companyStatusLabel;
}
Employee Status
#Entity(name = "employee_status")
#Table(name = "employee_status")
public class EmployeeStatus implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonProperty
#Column(name = "employee_status_id")
private Integer employeeStatusId;
#JsonProperty
#Column(name = "employee_status_name")
private String employeeStatusName;
// many other fields
}
CompanyStatusEmployeeStatus (Entity linking the 2 entities- one to one relationship)
#Entity(name = "company_status_employee_status")
#Table(name = "company_status_employee_status")
public class CompanyStatusEmployeeStatus implements Serializable {
// int(20)
#Id
#JsonProperty
#Column(name = "company_status_id")
private Integer companyStatusId;
// int(20)
#JsonProperty
#Column(name = "employee_status_id")
private Integer employeeStatusId;
}
I only want to return the necessary fields in my JSON response to the front end , so In order to do so I have created a smaller CompanyStatusDTO object that also has an EmployeeStatusDTO list nested
CompanyStatusDTO
public class CompanyStatusDTO {
#JsonProperty
private Integer companyStatusId;
#JsonProperty
private String companyStatusLabel;
#JsonProperty
private List <EmployeeStatusDTO> employeeStatusDTOs;
}
EmployeeStatusDTO
public class EmployeeStatusDTO {
#JsonProperty
private Integer employeeStatusId;
#JsonProperty
private String employeeStatusName;
}
However, I am relatively new to using Hibernate - is there a way that I can create a query that will map results directly from my MySQL DB to my CompanyStatusDTOobject?
If so, how can do I this?

you can directly map query result to you desired DTO using NativeQuery (datatype must match)
String q = "select ... from table"; // your sql query
Query query = getEntityManager().createNativeQuery(q, "EmployeeStatusDTO");
EmployeeStatusDTO data = (EmployeeStatusDTO) query.getSingleResult();
return data;

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.
If you adapt the CompanyStatus and CompanyStatusEmployeeStatus entities a bit and add the following:
public class CompanyStatus implements Serializable {
//...
#OneToMany(mappedBy = "companyStatus")
private Set<CompanyStatusEmployeeStatus> employeeStatuses;
}
public class CompanyStatusEmployeeStatus implements Serializable {
//...
#JsonProperty
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "company_status_id", insertable = false, updatable = false)
private CompanyStatus companyStatus;
#JsonProperty
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "employee_status_id", insertable = false, updatable = false)
private EmployeeStatus employeeStatus;
}
Your model could look like the following:
#EntityView(CompanyStatus.class)
public interface CompanyStatusDTO {
#IdMapping
Integer getCompanyStatusId();
String getCompanyStatusLabel();
#Mapping("employeeStatuses.employeeStatus")
List<EmployeeStatusDTO> getEmployeeStatusDTOs();
}
#EntityView(EmployeeStatus.class)
public interface EmployeeStatusDTO {
#IdMapping
Integer getEmployeeStatusId();
String getEmployeeStatusName();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
CompanyStatusDTO c = entityViewManager.find(entityManager, CompanyStatusDTO.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

You can try this:
public class Dao{
private SessionFactory sessionFactory;
public Dao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public <T> T save(final T o){
return (T) sessionFactory.getCurrentSession().save(o);
}
public void delete(final Object object){
sessionFactory.getCurrentSession().delete(object);
}
public <T> T get(final Class<T> type, final Long id){
return (T) sessionFactory.getCurrentSession().get(type, id);
}
public <T> List<T> getAll(final Class<T> type) {
final Session session = sessionFactory.getCurrentSession();
final Criteria crit = session.createCriteria(type);
return crit.list();
}
// and so on, you should get the idea
and you can then access like so in the service layer:
private Dao dao;
#Transactional(readOnly = true)
public List<MyEntity> getAll() {
return dao.getAll(MyEntity.class);
}

Related

How to sort by ManyToOne list in Pageable without duplicates?

I recently ran into this problem. I have a product that has a list of values in relation to volume. Example: enter image description here
Entities :
public class Price implements Serializable, Comparable<Price> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "product_id")
private Product product;
private int valume;
private int cost;
#Override
public int compareTo(Price o) {
if (this.valume > o.getValume()) {
return 1;
} else if (this.valume < o.getValume()) {
return -1;
} else {
return 0;
}
}
}
public class Product implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
private String description;
private LocalDateTime data;
#OneToMany(targetEntity = Price.class, mappedBy = "product",
cascade = CascadeType.ALL)
#LazyCollection(LazyCollectionOption.FALSE)
private List<Price> price = new ArrayList<>();
}
Controller :
#GetMapping
public String tapePage(#PageableDefault(size = 12, sort = "data", direction = Sort.Direction.DESC) Pageable pageable,
Model model){
model.addAttribute("products", productService.getAllProducts(pageable));
return "tape";
}
The problem is that if I want to sort a product by its cost, I will be given duplicate objects that have several values. Example - http://localhost:8080/?sort=price.valume,ASC
How can I implement a request that will issue products for non-duplicates with different prices. For example: http://localhost:8080/?sort=price[0].valume,ASC
That's not directly possible but you can achieve that with 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(Product.class)
public interface ProductDto {
#IdMapping
Long getId();
String getName();
String getDescription();
LocalDateTime getData();
#Mapping("MAX(prices.valume) OVER (PARTITION BY id)")
int getHighestValuem();
Set<PriceDto> getPrice();
#EntityView(Price.class)
interface PriceDto {
#IdMapping
Long getId();
int getValume();
int getCost();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
ProductDto a = entityViewManager.find(entityManager, ProductDto.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
Page<ProductDto> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary!
In your case, you could use a sort like this: sort=highestValuem,ASC

querydsl how to return dto list?

i use querydsl, hibernate
i want select data by Dto in Dto list but not working
here is my code
#Data
#Entity
public class Team {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
#Entity
#Setter
public class Member {
#Id
#GeneratedValue
private Long id;
private String name;
#ManyToOne
#JoinColumn(name = "team_id")
private Team team;
}
#Setter
public class TeamDto {
private Long id;
private String name;
private List<MemberDto> members = new ArrayList<>();
}
#Setter
public class MemberDto {
private Long id;
private String name;
}
test
#BeforeEach
void setup() {
queryFactory = new JPAQueryFactory(em);
Team team = new Team();
team.setName("teamA");
em.persist(team);
Member member = new Member("memberA");
member.setTeam(team);
em.persist(member);
Member member2 = new Member("memberB");
member2.setTeam(team);
em.persist(member2);
em.flush();
em.clear();
}
#Test
void t1() {
TeamDto teamDto = queryFactory
.select(Projections.fields(
TeamDto.class,
team.id,
team.name,
Projections.fields(
MemberDto.class,
member.id,
member.name
).as("members")
))
.from(team)
.fetchOne();
System.out.println("teamDto = " + teamDto);
}
error log is = java.lang.IllegalArgumentException: com.blog.querydsltest.domain.dto.MemberDto is not compatible with java.util.List
what is problem?? is impossible bring data by List dto??
i try to change Projections.fields to bean, construct, ... but not working
how can i do ?
Multi level aggregations are currently not supported by QueryDSL. There are also no concrete plans to support it as of now.
For a DTO solution that can fetch associations with it, I recommend you to have a look at Blaze-Persistence Entity Views. With Entity Views the code for your DTO would look something like the following:
#EntityView(Team.class)
public interface TeamDto {
#IdMapping public Long getId();
#Mapping("name") public String getName();
#Mapping("members") public List<MemberDTO> getMembers();
}
If members is not an association on your TeamEntity, you can map it through a #MappingCorrelated binding.
Disclaimer: I am a contributor for Hibernate, QueryDSL and Blaze-Persistence.

Need help learning how to join on two separate entities using jpa

A Java web project that uses Hibernate just fell into my lap. The original architect has left and I have almost no experience with JPA's Criteria API. So please forgive my ignorance. I'm looking for help with writing several joins using JPA's Criteria API.
I have the following entities and relationships. An ElectronicDevice contains a set of Components which contains a set of Signals.
I'm trying to write a query that returns all of the components and it's signals of a specific electronic device.
I can get the ElectronicDevice with the Component, but I'm unable to get the Signals. I have the following query written.
EntityManager em = getEm();
String electronicDeviceId="Some UUID";
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery(Component_.class);
Root<ElectronicDevice> i = cq.from(ElectronicDevice.class);
SetJoin<ElectronicDevice, Component> join = i.join(ElectronicDevice_.components);
cq.where(cb.equal(i.get(ElectronicDevice_.id), electronicDeviceId));
cq.multiselect(join);
TypedQuery q = em.createQuery(cq);
List<Component> resultList = q.getResultList();
My Entity Definitions are as follows
#Entity
public class ElectronicDevice implements Serializable {
#Id
#Column(length = 36)
private String id;
#XmlElement
#OneToMany
private Set<Component> components = new HashSet<Component>();
}
#Entity
public class Component extends ParametricObject implements Serializable{
#XmlElement
#OneToMany
private Set<Signal> signals = new HashSet<Signal>();
public Set<Signal> getComponents() {
return signals;
}
}
#Entity
public class Signal implements Serializable {
#Id
#Column(length = 36)
private String id;
}
public class ParametricObject {
#EmbeddedId
#XmlElement
private ParametricId id;
#XmlElement
private String name;
public ParametricId getId() {
return id;
}
public void setId(ParametricId id) {
this.id = id;
}
}
public class ParametricId {
#XmlElement
#ManyToOne
#XmlIDREF
private ElectronicDevice ed;
#XmlAttribute
#XmlID
#Column(length = 36)
private String internalId;
public ElectronicDevice getEd() {
return ed;
}
public void setEd(ElectronicDevice ed) {
this.ed = ed;
}
public String getInternalId() {
return internalId;
}
public void setInternalId(String internalId) {
this.internalId = internalId;
}
}
refer to the discussion at "Hibernate Criteria Join with 3 Tables". your query should looks likes this.
you must add ElectronicDevice with menyToOne annotation in the Component.(see the example at http://www.mkyong.com/hibernate/hibernate-one-to-many-relationship-example-annotation/.)
Criteria c = session.createCriteria(Component.class, "cmp");
c.createAlias("cmp.signals", "signal"); // this will do inner join
c.add(Restrictions.eq("cmp.electronicDevice", "xxxx"));
return c.list();

Spring JPA repository doesn't return List of entities

I try to get simple List of Rawtype entities with help of findBy method in the myMethod. But I get nothing - rawtypes doesn't contain any entity. Although findAll method works fine. Please tell we where is my mistake.
Rawtype.java
#Entity
#Table(name="rawtype")
public class Rawtype implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="rtid", nullable = false)
#GeneratedValue
private int rtId;
#Column(name="rtname", nullable = false)
private String rtName;
//getters and setters
RawtypeRepository.java
public interface RawtypeRepository extends JpaRepository<Rawtype, Integer> {
List<Rawtype> findByRtName(String rtName);
}
RawtypeServiceImpl.java
#Service
#Transactional
public class RawtypeServiceImpl implements RawtypeService {
#Autowired
RawtypeRepository rawtypeRepository;
public List<Rawtype> findAll() {
return rawtypeRepository.findAll();
}
public myMethod(){
List<Rawtype> rawtypes = rawtypeRepository.findByRtName("RawName");
}
}
Can you try printing rtName of all the entities returned by findAll() method? May be there isn't any record with 'RawName' as rtName.
Also, you can enable logging for JPA to see the generated query.

queryDSL entity's list contains all

So I have really been struggling to figure this out but there doesn't seem to be good documentation on how to do this. I have an entity RepairMan with a list of Skill entities. I need a query that can return a List<RepairMan> whose list of skills contain all the skill id's. Here is what the entities look like:
#Entity
#Table(name = "REPAIRMAN")
public class RepairMan implements Serializable
{
private static final long serialVersionUID = 8151638047721448259L;
#SequenceGenerator(name="REPAIRMAN_SEQ", sequenceName="REPAIRMAN_SEQ", allocationSize=1, initialValue=100)
#Id #GeneratedValue(generator="REPAIRMAN_SEQ")
private Long id;
#OneToMany
#JoinTable(name="REPAIRMAN_SKILLS", joinColumns=#JoinColumn(name="REPAIRMAN_ID"), inverseJoinColumns=#JoinColumn(name="SKILL_ID"))
private List<Skill> skills;
....
}
#Entity
#Table(name = "SKILL")
public abstract class Skill implements Serializable
{
private static final long serialVersionUID = -5272849377636005084L;
#SequenceGenerator(name="SKILL_SEQ_GEN", sequenceName="SKILL_SEQ", allocationSize=1, initialValue=100)
#Id
#GeneratedValue(generator="SKILL_SEQ_GEN", strategy=GenerationType.SEQUENCE)
private Long id;
#Column(name="NAME")
private String name;
#Column(name="DESCRIPTION")
private String description;
...
}
And here's the desired signature and what I have been able to work out in my mind:
public class RepairManRepositoryImpl extends QueryDslRepositorySupport implements RepairManRepositoryCustom
{
public CompanyInspectorRepositoryImpl()
{
super(RepairMan.class);
}
#Override
public List<RepairMan> getRepairMenByRequiredSkills(List<Long> skillIds)
{
PathBuilder<RepairMan> repairManPath = new PathBuilder<>(RepairMan.class, "repairman");
PathBuilder repairManSkillsPath = repairManPath.get("skills"); // probably wrong
BooleanBuilder hasAllSkills = new BooleanBuilder();
for (Long skillId : skillIds)
{
hasAllSkills.and(repairManSkillsPath.getNumber("id", Long.class).eq(skillId));
}
JPAQuery query = new JPAQuery(getEntityManager())
.from(repairManPath)
//need to join the repairManSkills somehow
.where(hasAllSkills);
return query.list(repairManPath);
}
}
I know this doesn't exactly work, plus I understand it would be easier to use the Qclasses but for compatibility reasons I can't do Qclasses.

Categories