I have a POJO something like this
Class BillEntity {
private int id;
private double amount;
private List<Integer> paymentIds;
}
I want to fetch this Object from DB using Hibernate criteria, currently I am having code something like this
DetachedCriteria criteria = DetachedCriteria.forClass(Bill.class);
//some Join aliases, which are working as expected
criteria.setProjection(Projections.projectionList()
.add(Projections.property("id") , "id")
.add(Projections.property("amount") , "amount");
criteria.setResultTransformer(new AliasToBeanResultTransformer(BillEntity.class));
criteria.list();
The id and amount are correctly populated, but I am unsure how paymentIds can be populated.
any pointers appreciated!
Related
In my data model there is an entity "location" which is recursively. Furthermore there are relations to other entities.
The corresponding JPA (Spring Data JPA) entity looks like:
#Entity
#Table(name = "location")
class Location{
#OneToMany(mappedBy = "parent", orphanRemoval = true)
#OrderBy("name ASC")
Set<Location> children = null
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "parent_id")
Location parent = null
#Column(name = "name")
String name = null
#OneToMany(mappedBy = "location", fetch = FetchType.EAGER)
Stops stops = null
...
What is the most performant way to do a read only query? I just need the information inside the entity (table location) with the complete recursive structure but no information from the related entities.
I've read the phrase DTO projection, but nothing about what to do with a recursive structure.
Reading a recursive structure is usually done by making use of what SQL calls a recuresive CTE. JPA does not support that out of the box, because not all RDBMS support it. If you know that your DBMS supports it, you can make use of the following SQL to do this:
WITH RECURSIVE nodes(id, parent_id) AS (
SELECT id, parent_id FROM location l where id = ?
UNION ALL
SELECT l.id, l.parent_id FROM nodes n JOIN location l ON n.parent_id = l.id
)
SELECT id, parent_id FROM nodes
With that you get a list of a specific and all parent location ids as well as their respective parents which is flat. You will have to bring structure into this.
List<Object[]> result = //get the result of the query
Map<Integer, LocationDto> locationMap = new HashMap<>();
result.forEach(r -> locationMap.put(result.get(0), new LocationDto(result[0], result[1])));
locationMap.values().forEach(l -> l.setParent(locaitonMap.get(l.getParentId())));
If you don't want to make use of plain SQL because of portability concerns or just because you don't want to give up on your abstraction, you can make use of Blaze-Persistence which works on top of JPA and adds support for CTEs. Your query with blaze-persistence would look like this
List<LocationCte> result = criteriaBuilderFactory.create(entityManager, LocationCte.class)
.withRecursive(LocationCte.class)
.from(Location.class, "l")
.bind("id").select("l.id")
.bind("parent").select("l.parent.id")
.where("id").eq(initialId)
.unionAll()
.from(Location.class, "l")
.innerJoinOn(LocationCte.class, "cte")
.on("cte.parent").eqExpression("l.id)
.end()
.bind("id").select("l.id")
.bind("parent").select("l.parent.id")
.end()
.from(LocationCte.class)
.getResultList();
You will also need this special entity class
#CTE
#Entity
public class LocationCte {
#Id Integer id;
Integer parent;
}
I want to search on a collection of string in an entity but my query was so slowly so i decide to create index on this collection.
Can I index on collection of String in hibernate ? and how can i do it . I use #OrderColumn but it makes error.
#Entity
Class A {
#ElementCollection
private List<String> something;
}
I have the below pojo which contain many attributes and corresponding setters and getters
public class TOAAarty
{
protected long id;
private long version;
//corresponding setters and getters
}
now i have fire the below query which bring distinct records from the data base
select distinct(id) from toa_arty // so this query bring the distincr ids's
now in the similar fashion i want to rite HQL for this in hibernate to achieve the same as above query so what i have tried is that basically there will be a method which will populate the list with the ids as output
so what i have tried is shown below please advise is it correct and is there any other better approach to achieve the same
public List<Long> findDistinctRrokerIds()
{
Criteria query = session.createCriteria(TOAAarty.class);
ProjectionList proList = Projections.projectionList();
proList.add(Projections.property("id"));
query.setProjection(Projections.distinct(proList));
return (List<Long>) criteria.list(); query.list();
}
I have a simple parent-child relationship witin the same class. I like to get all instances where no parent exists (= NULL).Means the "root" categories.
I need to use criteria query and can not use HQL or SQL. Due an issue with Relationship and "isNull" Operation it seems that the criteria query can not be "normally" be used as expected and require some trick. Anybody has any hints which I can try?
#Entity
public class Category {
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "parent_id")
private Category parent;
#OneToMany(cascade=CascadeType.ALL, mappedBy="parent", fetch=FetchType.EAGER)
#OrderBy(value="pos")
private List<Category> childs = new ArrayList<Category>();
...
}
If I use the following criteria query construct I get strange result back. I get multiple times the same category instances instead just the "root" ones.
Criteria c = session.createCriteria(Category.class, "c");
c.add(Restrictions.isNull("c.parent"));
List<Category> rootCategories = c.list();
for(Category category : rootCategories) {
logger.info(category);
}
I tried already some constructs with aliases but no luck. Left Join or inner join will not work ;(
Criteria c = session.createCriteria(Category.class, "c");
c.createAlias("c.parent", "p", JoinType.RIGHT_OUTER_JOIN);
c.add(Restrictions.isNull("p.id"));
List<Category> rootCategories = c.list();
for(Category category : rootCategories) {
logger.info(category);
}
In case I use HQL (which isunfortunately no option for my issue) it works perfectly
List<Category> rootCategories = session.createQuery("FROM Category c where c.parent is null order by c.pos").list();
Thank you for any hints in advance
Let's say we have:
#Entity public class Order {
#Id private int id;
#OneToMany(mappedBy="order") private List<Item> items;
...
}
and
#Entity public class Item {
#Id private int id;
#ManyToOne private Order order;
...
}
And let's say there is 10.000 orders with each having 20 items.
We need to iterate thought all order and all their items.
What is the best way to do it in JPA?
My issue is, if I just iterate the elements like:
for (Order order: em.createTypeQuery("select o from Order o", Order.class).getResultList()) {
report.printOrder(order);
for (Item item: order.getItems()) {
report.printOrderItem(item);
}
}
it will result in 10.001 sql queries:
1 time: select * from order
10.000 times: select * from item where order_id = ?
Is there any way to optimize it? Two queries? One query?
(We are using EclipseLink)
Thanks.
You may also want to consider the EclipseLink query Hint "eclipselink.batch" with value "o.items". This results in two queries but can be more effecient than once large joined query.
You may use join fetch (this also requires distinct since join fetch have a join semantics):
select distinct o from Order o join fetch o.items