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;
}
Related
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!
I have #OneToMany association between 2 entities (Entity1 To Entity2).
My sqlQueryString consists of next steps:
select ent1.*, ent2.differ_field from Entity1 as ent1 left outer join Entity2 as ent2 on ent1.item_id = ent2.item_id
Adding some subqueries and writing results to some_field2, some_field3 etc.
Execute:
Query sqlQuery = getCurrentSession().createSQLQuery(sqlQueryString)
.setResultTransformer(Transformers.aliasToBean(SomeDto.class));
List list = sqlQuery.list();
and
class SomeDto {
item_id;
some_filed1;
...
differ_field;
...
}
So the result is the List<SomeDto>
Fields which are highlighted with grey are the same.
So what I want is to group by, for example, item_id and
the List<Object> differFieldList would be as aggregation result.
class SomeDto {
...fields...
List<Object> differFieldList;
}
or something like that Map<SomeDto, List<Object>>
I can map it manually but there is a trouble:
When I use sqlQuery.setFirstResult(offset).setMaxResults(limit)
I retrieve limit count of records. But there are redundant rows. After merge I have less count actually.
Thanks in advance!
If you would like to store the query results in a collection of this class:
class SomeDto {
...fields...
List<Object> differFieldList;
}
When using sqlQuery.setFirstResult(offset).setMaxResults(n), the number of records being limited is based on the joined result set. After merging the number of records could be less than expected, and the data in List could also be incomplete.
To get the expected data set, the query needs to be broken down into two.
In first query you simply select data from Entity1
select * from Entity1
Query.setFirstResult(offset).setMaxResults(n) can be used here to limit the records you want to return. If fields from Entity2 needs to be used as condition in this query, you may use exists subquery to join to Entity2 and filter by Entity2 fields.
Once data is returned from the query, you can extract item_id and put them into a collection, and use the collection to query Entity 2:
select item_id, differ_field from Entity2 where item_id in (:itemid)
Query.setParameterList() can be used to set the item id collection returned from first query to the second query. Then you will need to manually map data returned from query 2 to data returned from query 1.
This seems verbose. If JPA #OneToMany mapping is configured between the 2 entity objects, and your query can be written in HQL (you said not possible in comment), you may let Hibernate lazy load Entity2 collection for you automatically, in which case the code can be much cleaner, but behind the scenes Hibernate may generate more query requests to DB while lazy loading the entity sitting at Many side.
The duplicated records are natural from a relational database perspective. To group projection according to Object Oriented principles, you can use a utility like this one:
public void visit(T object, EntityContext entityContext) {
Class<T> clazz = (Class<T>) object.getClass();
ClassId<T> objectClassId = new ClassId<T>(clazz, object.getId());
boolean objectVisited = entityContext.isVisited(objectClassId);
if (!objectVisited) {
entityContext.visit(objectClassId, object);
}
P parent = getParent(object);
if (parent != null) {
Class<P> parentClass = (Class<P>) parent.getClass();
ClassId<P> parentClassId = new ClassId<P>(parentClass, parent.getId());
if (!entityContext.isVisited(parentClassId)) {
setChildren(parent);
}
List<T> children = getChildren(parent);
if (!objectVisited) {
children.add(object);
}
}
}
The code is available on GitHub.
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();
}
Is it possible to store a list of integers in a single field of the respective entity table with standard JPA 2?
#Entity
#Table(name="tbl_myentities")
public class MyEntity {
#ElementaryCollection
#Column(name="vals") // in table tbl_myentities
private List<Integer> vals;
It is not possible to store multiple values in a single field. Whats the reason behind storing them in a single field?
A way could be to use a field of type String and add all integers there in a comma separated list and join/explode in getters and setters:
private String vals;
public setVals(int vals[])
{
// this.vals = Iterate vals[] and create a comma separated string
}
public int[] getVals()
{
// vals.split(",") to get a list of Strings, then typecast/parse them to ints before returning
}
Using the #ElementCollection annotation and #CollectionTable to control the mappings requires a separate table to store the values in.
#ElementCollection
private Collection<Integer> integers;
Read more about element collections on on http://en.wikibooks.org/wiki/Java_Persistence/ElementCollection
Similar question here Does JPA #ElementCollection annotation always produce an one-to-many relationship?
You can create a converter and use it with the annotation #Converter.
This converter must implement AttributeConverter which is a generic interface with two methods convertToDatabaseColumn and convertToEntityAttribute.
It is pretty easy to work with, you can check here: jpa independent custom type mapping / javax.persistence.x alternative to org.hibernate.annotations.Type and org.hibernate.annotations.TypeDef
You can store all the vals in a String field, separated with a comma, and change associated getter and setter like that :
public List<Integer> getVals() {
List<Integer> lstVals = new ArrayList<Integer>();
int val = 0;
for(String field : this.vals.split(",")) {
try {
val = Integer.parseInt(field);
}
// If the String contains other thing that digits and commas
catch (NumberFormatException e) {
}
lstVals.add(val);
}
return lstVals;
}
public void setVals(List<Integer> vals) {
String newVals = "";
for(int i : vals) {
newVals.concat(String.valueOf(i));
}
this.vals = newVals;
}
I don't think that's possible. Because you can not have a column in a database table that allows you to store list of integers.
What you can do is use a string type field instead of list of integers -
#Column(name="vals") // in table tbl_myentities
private String vals;
And do the conversion to string from list of integers and back manually before you save your entity and after you have read your entity.
Maybe a #Lob could suit you ? (despite what it imply)
#Lob
ArrayList<String> vals;
(note that your collection must be explicitly an ArrayList)
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