Below is the query used to fetch details from the employee table and address table. There more columns in the tables which as of now not required.
SELECT
e.id,
e.name ,
e.address_id,
a.city
FROM
employee e,
address a
WHERE
e.id = 1
AND a.id = e.address_id;
How to run this query using spring JPA, and map it to a model class as below?
public class Employee {
long id;
Stirng name;
String city;
long addressId;
}
Related
Here are my entities:
#Entity
public class Author {
#Id
private Long id;
//...
}
and
#Entity
public class Book {
#Id
private Long id;
#ManyToOne(optional = true)
#JoinColumn(name = COLUMN_AUTHOR_ID, referencedColumnName = "id")
private Author author;
//...
}
I don't want to declare the Set<Book> books field in the Author entity to avoid unnecessary data fetch. I already know about fetch = FetchType.LAZY, but I have some cases in which even the lazy fetching is triggered.
Here is my question: How can I use JPQL join to retrieve the relationship in a custom query?
Look at ??books?? in the below query:
entityManager.createQuery("SELECT new " + AuthorWithBooks.class.getName() +
"(a.id, ..., group_concat(b.name)) FROM Author a LEFT JOIN a.??books?? b GROUP BY a.id", AuthorWithBooks.class);
You should consider that there might be some Author with no book and I want to include them in my query! So I can not start my join from Book.
Thanks
Simply switch the from and join clause:
entityManager.createQuery("SELECT new " + AuthorWithBooks.class.getName() +
"(a.id, ..., group_concat(b.name)) FROM Book b " +
"RIGHT JOIN b.author a GROUP BY a.id", AuthorWithBooks.class);
Given this very simple DTO:
#Entity
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
#OneToOne
private Employee boss;
}
I'd like to make a query that gathers all employee names and their boss' id, put in a nice clean POJO:
public class EmployeeInfo {
private String name;
private Long bossId;
public EmployeeInfo(String name, Long bossId) {
this.name = name;
this.bossId = bossId;
}
}
This query should be of use:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<EmployeeInfo> query = cb.createQuery(EmployeeInfo.class);
Root<Employee> root = query.from(Employee.class);
query.select(
cb.construct(EmployeeInfo.class,
root.get("name").as(String.class),
root.get("boss").get("id").as(Long.class)));
result = em.createQuery(query).getResultList();
When a bossId is present in the employee column this works just fine. But when no boss id is set the record will be completly ignored. So how do i treat this non existing boss relation as null or 0 for the construct/multiselect?
In pure SQL it is easy:
SELECT name, COALESCE(boss_id, 0) FROM EMPLOYEE;
But for the love of god i cannot make the criteria api do this.
cb.construct(EmployeeInfo.class,
root.get("name").as(String.class),
cb.coalesce(root.get("boss").get("id").as(Long.class), 0L)));
The problem is that root.get("boss") generate query with cross join like this from Employee employee, Employee boss where employee.boss.id=boss.id. So records where employee.boss.id is null are ignored.
To solve the problem you should use root.join("boss", JoinType.LEFT) instead of root.get("boss")
I have two entities: Group and Student which is ManyToMany relation, Group is the owner。
Now define a GroupRepository extends from JpaRepository and want to declare a method using #Query annotation to directly get Student list given a GroupId. How?
The method return value should be List or Page, just no idea how to define using query language.
I know how to get a Group entity with eagerly fetch all Students with that Group like below:
#Query("select group from Group group left join fetch group.students where group.id=:id")
Group findOneWithEagerRelationships(#Param("id") Long id);
Very appreciated for any help.
If you have a model like this:
#Entity
class Group {
#Id Ling id;
#ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Student> students;
//...
}
#Entity
class Student {
#Id Long id;
#ManyToMany(mappedBy = "groups")
private List<Group> groups;
//...
}
Then to get all students through the group repo you can make a method like this:
interface GroupRepo extends JpaRepository<Group, Long> {
#Query("select s from Group g join g.students s where g.id = ?1")
Page<Student> getAllStudentsByGroupId(Long groupId, Pageable pageable);
}
Sources: 1, 2.
Having two entity classes with a many to many relation, I am trying to create query which tests the existence of any relationship for all entities from one table. I am stuck because it seems that there is no way to refer to the JoinTable through the Criteria API.
Example entities:
#Entity
#Table(name="man")
public class Man {
#Id
#GeneratedValue
private Long id;
}
#Entity
#Table(name="woman")
public class Woman {
#Id
#GeneratedValue
private Long id;
#ManyToMany
#JoinTable(
name="man_woman",
joinColumns=
#JoinColumn(name="woman_id", referencedColumnName="id"),
inverseJoinColumns=
#JoinColumn(name="man_id", referencedColumnName="id")
)
private Set<Man> men;
}
I would like to create a query using criteria API which would result in SQL such as:
select m.id,
case when exists(select * from man_woman mw where mw.man_id=m.id) then 1 else 0
from man;
The best I have come up with so far is the following:
CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();
Root<Man> from = criteriaQuery.from(Man.class);
Subquery<Long> subquery = criteriaQuery.subquery(Long.class);
Root<Woman> sub_from = subquery.from(Woman.class);
SetJoin<Woman, Man> setJoin = sub_from.join(Woman_.men);
subquery.select(sub_from.get(Woman_.id));
subquery.where(from.in(setJoin.get(Man_.id)));
criteriaQuery.multiselect(from.alias("man_entity"),
criteriaBuilder.selectCase()
.when(
criteriaBuilder.exists(subquery)
, true)
.otherwise(false)
.alias("knows_any_women")
);
return em.createQuery(criteriaQuery).getResultList()
which results in SQL containing extra joins:
select m.id,
case when exists(select w.id
from woman w
inner join man_woman mw on w.id = mw.woman_id
inner join man m2 on m2.id = mw.man_id
where m.id in (m2.id)
)
then 1 else 0
from man;
I guess this statement would eventually be optimized to look like my desired one - but is there a way to make it simpler from the beginning?
Mainly I work with JSF so am totally new to this annotation subject
If anyone can help
I wanna a list from this query
SELECT f.CODE ,f.NAME || '-' || e.NAME
FROM FS.ELIGIBLE e RIGHT
OUTER JOIN FS.FINANCIAL_SUPPORT f ON e.CODE = f.CODE ;
The query above retrieves a list from 2 tables and concatenating the name field from both tables!!
How can i do this in JPA or in play with another query supported by Play Framework ???
Have a read of the Play Framework documentation, specifically the part about JPA and your Domain Model.
You can access the entity manager at any time by calling
EntityManager entityManager = JPA.em();
Using this you can create any query that you want, even a "Native" Query. For example:
List<Object> results = JPA.em().createNativeQuery(
"SELECT f.CODE ,f.NAME || '-' || e.NAME "+
"FROM FS.ELIGIBLE e RIGHT "+
"OUTER JOIN FS.FINANCIAL_SUPPORT f ON e.CODE = f.CODE").getResultList()
JPA is not like relational database system which you can do your queries like join, left join or outer joins it is a mapping technology of objects. You can also do the same fetch just like those RDBMS counterparts but with a different approach.
What you have to do is make an Object then relate your second Object to your first Object, that is the proper way to relate 2 or more Objects. The Objects I'm talking about is your Table. See my example below:
Table1: Items.java
...
// do your imports here ...
// do your annotations here like
#Entity
#Table(name="Items")
public class Items implements Serializable {
private String id;
private String itemno;
private String description;
private Set<Vendors> vendors; //this is the 2nd table (1:n relationship)
...
// don't forget your constructor
// in your setter and getter for Vendors do the ff:
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name="id")
public Set<Vendors> getVendors() {
return vendors;
}
public void setVendors(Set<Vendors> vendors) {
this.vendors = vendors;
}
...
}
Table2: Vendors.java
#Entity
#Table(name="Vendors")
public class Vendors implements Serializable {
private long id;
private String company;
private String contact;
private String sequence;
...
public Vendors() { }
...
// in your setter & getter
#Id
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
...
}
Now on your query, just do a regular select as in the ff:
public void makeQuery(String seq) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory(...);
EntityManager em = emf.createEntityManager();
TypedQuery<Items> query = em.createQuery("
SELECT i, j.contact, j.company, j.sequence FROM Items i LEFT OUTER JOIN i.vendors j WHERE i.vendors.sequence = :seq
ORDER BY i.id", Items.class);
List<Items> items = query.setParameter("sequence", seq).getResultList();
...
}
Now you can refer to your 2nd table Vendors by using items.vendors.company ... and so on.
One disadvantage with this one is that, JPA make its related objects in the form of Set, see the declaration in Table1 (Items) - private Set vendors. Since it was a Set, the sequence is not in order it was received, unlike using List.
Hope this will help ...
Regards, Nelson Deogracias