queryDSL entity's list contains all - java

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.

Related

How to create an api like this 'GET host:///api?user.username=bug' in Springboot?

I saw this kind of API style once and it worked proper
Noob here and I am current learning RESTful stuff,If anyone who may gives some advice and instruction.I'd be very appreciate!
Get URL
//The argument isn't mandatory, May be order.orderInfo,order.orderPrice etc
http://localhost:8080/order?order.orderNo=123
Controller code
#GetMapping
CollectionModel<Order> getOrders(Order order) {
List<Order> ordersResult = orderService.getOrders(order);
for (Order result : ordersResult) {
Link selfLink = WebMvcLinkBuilder.linkTo(OrderController.class).slash(result.getId()).withSelfRel();
result.add(selfLink);
}
Link link = WebMvcLinkBuilder.linkTo(OrderController.class).withSelfRel();
return CollectionModel.of(ordersResult, link);
}
Entity code
public class Order extends RepresentationModel<Order> implements Serializable {
#Id
#GeneratedValue
#Column(unique = true)
private Integer id;
private Long orderNo;
}
And my jpa repository
public interface OrderRepository extends JpaRepository<Order, Integer>,PagingAndSortingRepository<Order, Integer> {
}
I have finally figured out that this kind of URL is not work this way.
Shoud be apply to a specific situation.Which is the get endpoint method has a 'Relative Object'.Then we may use URL like this to improve flexable api.
Talk is cheap,I'll show you the code!
Entity->Customer
public class Customer extends RepresentationModel<Customer> implements Serializable {
#Id
#GeneratedValue
#Column(unique = true)
private Integer id;
private String name;
//Add relative Object to entity.
#OneToOne
private Order order;
}
Entity->Order
public class Order extends RepresentationModel<Order> implements Serializable {
#Id
#GeneratedValue
#Column(unique = true)
private Integer id;
private Long orderNo;
//Add relative Object to entity.
#OneToOne
private Customer customer;
}
Endpoint->CustomerController/getMethod
#GetMapping
CollectionModel<Customer> getCustomers(Customer customer) {
List<Customer> customersResult =
customerService.getCustomers(customer);
for (Customer result : customersResult) {
Link selfLink = WebMvcLinkBuilder.linkTo(CustomerController.class).slash(result.getId()).withSelfRel();
result.add(selfLink);
}
Link link = WebMvcLinkBuilder.linkTo(CustomerController.class).withSelfRel();
return CollectionModel.of(customersResult, link);
}
URL
scheme://[api]/[order.orderNo=123]
Then the value will mapping to paramter-custoemr inside.
PS:HTTP method '#fragment' may suitable for this case.
Thanks to #JRichardsz :)

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.

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

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);
}

Does extending a base class and both classes having #Id annotation cause Repeated column in mapping for entity?

I have two classes.
One class extends the other.
Both classes will be persisted in the database.
Why am I still getting : Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.ct.www.model.Bt column: q_Id (should be mapped with insert="false" update="false")
Questions.class
#Entity
#Table(name="Questions")
#Access(value = AccessType.FIELD)
public class Questions implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
//#Access(value= AccessType.FIELD)
private String q_Id;
#Column(name="q_type")
private String q_Type;
#Column(name="q_lang")
private String q_lang;
#Access(value = AccessType.PROPERTY)
public String getQ_Type() {
return q_Type;
}
public void setQ_Type(String q_Type) {
this.q_Type = q_Type;
}
#Id
#Column(name="q_Id")
#GeneratedValue(generator = "uuid2")
#GenericGenerator(name = "uuid2", strategy = "uuid2")
#Access(value = AccessType.PROPERTY)
public String getQ_Id() {
return q_Id;
}
public void setQ_Id(String q_Id) {
this.q_Id = q_Id;
}
#Access(value = AccessType.PROPERTY)
public String getQ_lang() {
return q_lang;
}
public void setQ_lang(String q_lang) {
this.q_lang = q_lang;
}
}
BT.class
#Entity
#Table(name="BT")
#Access(value = AccessType.FIELD)
public class BT extends Questions implements Serializable{
private static final long serialVersionUID = 1L;
#Access(value = AccessType.FIELD)
// #Id
// #Column(name="q_Id")
private String q_Id;
#Access(value = AccessType.PROPERTY)
public String getQ_Id() {
return q_Id;
}
public void setQ_Id(String q_Id) {
this.q_Id = q_Id;
}
// #OneToOne(cascade = CascadeType.ALL)
// #PrimaryKeyJoinColumn
// #JoinColumn(name="q_id")
// #MapsId
private Questions question;
public Questions getQuestion() {
return question;
}
public void setQuestion(Questions question) {
this.question = question;
}
}
One of my use case is
Questions and BT will be persisted separately into corresponding tables in MySQL (Questions table and BT table).
BT is a type of Question. So I decided to extend it.
Both table has a primary key which is Id, and my DAO class will first insert in Questions table and use same Id for BT class which later inserts into BT table.
Extending a base class which is an Entity will cause this problem.
You can:
Remove the common mapped fields/properties from the child class
Add #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) above parent class for your use case.
Refer to Section 2.11.4 in Hibernate-5.3.1.Final User Guide for example code.
If you need different generation strategy in parent and child, you can override the getQ_Id() method in child and implement that.

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();

Categories