Create query which selects by checking items in related list - java

I have Shop entity:
#Entity
#Table(name = "shop")
public class Shop {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name="shop_id")
private List<OpenDay> openDays = new ArrayList<>();
}
and OpenDay entity:
#Entity
#Table(name = "open_day")
public class OpenDay {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDate date;
}
I need a query which will select all Shop which have OpenDay with date set to particular dates, let's say for today and tomorrow so I select shops which are open today and tomorrow.
How can I achieve this?
Criteria API is preferred so I will be able to use it with spring-data-jpa Specification. Thank you.

As far as I understand open_day table contains shop_id column. So I suggest you to add Shop field to OpenDay entity.
#Entity
#Table(name = "open_day")
public class OpenDay {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDate date;
#ManyToOne
#JoinColumn(name="shop_id")
private Shop shop;
}
And then
EntityManager entityManager;
public List<Shop> getShopsByOpenDates(List<LocalDate> dates) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Shop> query = builder.createQuery(Shop.class);
Root<OpenDay> openDay = query.from(OpenDay.class);
Predicate predicate = openDay.get("date").in(dates);
query.select(openDay.get("shop")).distinct(true).where(predicate);
return entityManager.createQuery(query).getResultList();
}

Related

How use projections in spring-data-jpa?

I need to get all the information about the ticket in one request, also the name, author, and year of the book. I have implemented this :
I create interface TicketWithBookView
public interface TicketWithBookView {
Date getGiveAway();
Long getReaderId();
Date getTake();
interface Book {
String getAuthor();
String getName();
Integer getYearCreation();
}
}
My entities TicketEntity
#Data
#Entity
#Table(name = "ticket")
#NoArgsConstructor
#AllArgsConstructor
public class TicketEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private Long readerId;
#Column(nullable = false)
private Long bookId;
#Column(nullable = false)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date take;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date giveAway;
}
And second entity BookEntity;
#Entity
#Data
#NoArgsConstructor
#Table(name = "book")
public class BookEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String author;
private Integer yearCreation;
private Integer count;
}
And repository
#Repository
public interface TicketRepository extends CrudRepository<TicketEntity, Long> {
List<TicketWithBookView> findAllByGiveAwayIsNullAndTakeIsNotNull();
}
No way) Projections are used to select data from a query, and not to obtain data from other tables.
You can upload data from another table and create a new model in the service.
probably problem is with AAnd in method name
findAllByGiveAwayIsNullAAndAndTakeIsNotNull
add error message that you get, It would be easier to find problem

Hibernate one to one criteria fetching

I am using hibernate one to one mapping between car and person table. But a person might have car and might not have a car. now while fetching the records from the person table using hibernate criteria , I want to fetch only those persons who have a car, i.e only those entries in person table for which a corresponding entry in car table exists. How this can be done using hibernate criteria/alias?
Below is the piece of code. kindly help with the criteria or alias that has to written to fetch result:
#Getter
#Setter
#Entity
#Table(name = "Person")
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Person_ID")
private Long personId;
#OneToOne(mappedBy = "personAsset", cascade = CascadeType.ALL)
private Car car;
}
#Getter
#Setter
#Entity
#Table(name = "Car")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Car_ID")
private Long carId;
#OneToOne
#JoinColumn(name = "Person_ID")
private Person personAsset;
}
what you are looking for is the cascadeType orphanRemoval=true on the #OneToOne annotation.
here is your class how would look like :
#Getter
#Setter
#Entity
#Table(name = "Car")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Car_ID")
private Long carId;
#OneToOne(fetch=FetchType.EAGER , cascade=CascadeType.ALL, orphanRemoval=true)
#JoinColumn(name = "Person_ID")
private Person personAsset;
}
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> query = cb.createQuery(Person.class);
Root<Person> person = query.from(Person.class);
Predicate predicate = cb.isNotNull(person.join("car"));
predicates.add(predicate );

Loading DTO with collection

#Entity
#Table(name = "person")
public class Consignment implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "person_id")
private String personId;
#Column(name = "person_name")
private String personName;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "person")
#Column(name = "cars_owned")
private Set<Cars> casrsowned = new HashSet<>();
}
#Entity
#Table(name = "cars")
public class Cars implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "cars_id")
private String carsId;
#ManyToOne
#JoinColumn(name = "person")
private Person person;
#OneToOne
private CarsDetail carsDetail;
}
#Entity
#Table(name = "carsDetail")
public class CarsDetail implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "brand")
private String brand;
#Column(name = "color")
private String color;
#Column(name = "model")
private String model;
}
class CarModelDTO {
String personName;
List<String> models;
}
In the above relation, want to return CarModelDTO
JPA query where,
#Query("Select CarModelDTO(p.personName, p.casrsowned.carsDetail.model) from Person as p where p`enter code here`.id = :id"))
public CarModelDTO getCarmodelOwnedByAperson(#Param("id") Long id);
I tried multiple ways but it gives
org.hibernate.QueryException: illegal attempt to dereference collection
As I have already described Retrieve List from repository interface to DTO list you should go through the following step :
first create a constructor using the fields you want to be returned from the query output
in you query you should create new instance of your dto and pass the field from db to new instalnce :
so you need these changes:
1. In the constructor:
You should not use a list as List<String> models; as you should consider that your dto as a result row of DB. so you need to have a simple String model;
public CarModelDTO (String name,String model){
this.name=name;
this.model=model;
}
2. In the #Query:
you should use multi inner join appropriately
you should also append your package name to CarModelDTO in the query (here i used com.example you should change it)
#Query("Select com.example.CarModelDTO(p.personName, d.model ) from Person as p inner join p.carsowned c inner join c.carDetail d where p`enter code here`.id = :id"))
public CarModelDTO getCarmodelOwnedByAperson(#Param("id") Long id)

JPA Criteria seems to ignore join on condition

I've a User and Contact entities in my app and I need to every user can add some private comment about every contact and that comment must be available only for that user. So I create new entity - PrivateInfo. Here's the code.
User class:
#Entity
#Table(name = "users")
#XmlAccessorType(XmlAccessType.FIELD)
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String login;
// other fields
}
Contact class:
#Entity
#Table(name = "contacts")
#XmlAccessorType(XmlAccessType.FIELD)
public class Contact implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#OneToMany(fetch = LAZY, cascade = ALL, mappedBy = "contact")
private Set<PrivateInfo> privateInfo;
// etc.
}
PrivateInfo class:
#Entity
#Table(name = "private_info")
#XmlAccessorType(XmlAccessType.FIELD)
public class PrivateInfo implements Serializable {
#EmbeddedId
private PrivateInfoKey pk;
#Column(name = "additional_info")
private String additionalInfo;
#ManyToOne(fetch = FetchType.EAGER)
#MapsId("contactId")
private Contact contact;
}
#Embeddable
public class PrivateInfoKey implements Serializable {
#Column(name = "contact_id")
private Long contactId;
#Column(name = "user_id")
private Long userId;
}
I'm using Spring Data repositories with JpaSpecificationExecutor for querying so here's my attempt to write specification for getting all contacts with private info for specific user.
public static Specification<Contact> withPrivateInfo(final long userId) {
return new Specification<Contact>() {
#Override
public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Join<Contact, PrivateInfo> joinPrivateInfo = root.join(Contact_.privateInfo, JoinType.LEFT);
joinPrivateInfo.on(cb.equal(
joinPrivateInfo.get(PrivateInfo_.pk).get(PrivateInfoKey_.userId), userId
));
return cb.conjunction(); // translates in sql like '... where 1 = 1'
}
};
}
However, when I call
contactRepository.findAll(withPrivateInfo(1));
I'm receiving contacts and each of them contains in privateInfo field all users information about this contact (not only for user with id = 1, as expected). Seems like join on condition ignored.
Any suggestions how to achieve my goal? Maybe with another entities structure. Is this possible with JPA/Criteria?

Hibernate QueryException: could not resolve property

So I have these relations between these 3 tables
And what I'm trying to do is to search (by code or designation) and get list of projects for a specific chief, something like this:
SELECT * FROM Project p JOIN ProjectHasChief phc ON (p.id = phc.idproject)
JOIN Chief c ON (c.id = phc.id_chief)
WHERE c.id = (myID)
AND (designation LIKE '%user_string%' OR code LIKE '%user_string%');
AND since I'm using hibernate I've used Criteria:
Criteria c = session.createCriteria(ProjectHasChief.class);
c.add(Restrictions.eq("chief", chief))
.add(Restrictions.disjunction()
.add(Restrictions.like("project.designation", reg, MatchMode.ANYWHERE))
.add(Restrictions.like("project.code", reg, MatchMode.ANYWHERE)));
List<ProjectHasChief> list = (List<ProjectHasChief>)c.list();
But I get this error:
org.hibernate.QueryException: could not resolve property: project.designation of: smt.agm.entities.ProjectHasChief
Project entity:
#Entity
#Table(name="projet")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", columnDefinition="serial")
private int id;
#Column(name="code")
private String code;
#Column(name="designation")
private String designation;
#OneToMany(cascade = CascadeType.ALL, mappedBy="project", orphanRemoval=true)
#OrderBy(clause="id DESC")
private List<ProjectHasChief> chiefs = new ArrayList<ProjectHasChief>();
}
Chief entity:
#Entity
#Table(name="chief")
public class Chief {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", columnDefinition="serial")
private int id;
#Column(name = "name")
private String name;
}
ProjectHasChief entity:
#Entity
#Table(name="mapping_chantier_chef")
public class ProjectHasChief {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", columnDefinition="serial")
private int id;
#ManyToOne
private Project project;
#ManyToOne
private Chief chief;
#Column(name="date_deb")
private Date startDate;
#Column(name="date_fin")
private Date endDate;
}
Whe hibernate don't know the property designation of Project entity ?!!
Are you absolutely sure all the mappings and joins actually work?
If so, you can try to declare an implicit alias for Project like so:
Criteria c = session.createCriteria(ProjectHasChief.class);
c.createAlias("project", "project") //THIS ONE
c.add(Restrictions.eq("chief", chief))
c.add(Restrictions.disjunction()
.add(Restrictions.like("project.designation", reg, MatchMode.ANYWHERE))
.add(Restrictions.like("project.code", reg, MatchMode.ANYWHERE)));
List<ProjectHasChief> list = (List<ProjectHasChief>)c.list();

Categories