I have Bill and Bill_Details with onetomany and manytoone Relationship. I need a help in getting Bill List.
Pojo
Bill
#OneToMany(cascade={CascadeType.ALL},fetch = FetchType.EAGER)
#JoinColumn(name = "bill_id")
private Set<BillDetails> billDetails = new HashSet<BillDetails>();
BillDetails
#ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
#JoinColumn(name = "bill_id")
private Bill billId;
I am using Projections to take Bill value from List.
DaoHibernate
#Transactional
public List<Bill> getbillDetailsByBillId(String billId) {
Criteria cr = null;
try {
cr = getSession().createCriteria(Bill.class,"bill")
.createAlias("bill.billDetails","billDetails")
.setProjection(Projections.projectionList()
// I tried .setProjectionProjections.distinct(Projections.projectionList()
.add(Projections.property("billNo"),"billNo")
.add(Projections.property("billDetails.amount"),"billDetails.amount")
.add(Projections.property("billDetails.rate"),"billDetails.rate"))
.add(Restrictions.eq("id", billId))
.setResultTransformer(new AliasToBeanNestedResultTransformer(Bill.class));
} catch (Exception e) {
System.out.println("Get bill DetailsByBillId Error----------"+e);
e.printStackTrace();
}
System.out.println(cr.list().size());
return cr.list();
}
Note:
-- > Bill table contains single row
-- > BillDetails table contains four row for this BillId
My criteria Query Returns four Objects instead of single Object. I also tried with distinct feature.
Expected Output :
I need single object that contains BillDetails Objects(4 Values).
ie.I explained with sample Json format below
{billNo:231,
billDetails[{amount:100,rate:1}{amount:200,rate:2}
{amount:300,rate:30}{amount:400,rate:4}] }
How to get this by Hibernate criteria Query ? Please Help
First of all, your mapping isn't correct. You have a bidirectional association, and one of the side (the one side) must be the inverse of the one side:
#OneToMany(mappedBy = "billId", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<BillDetails> billDetails = new HashSet<BillDetails>();
You should also rename the field billId to bill, given that what it contains is a bill, and not a bill ID.
Now, the problem with your query is that you're using projections for no reason. When using projections, you deliberately choose to return rows containing individual columns. And since the SQL query returns 4 rows you get back 4 bills: one for each row.
You're also making your life unnecessarily complicated by using a Criteria query instead of HQL, which is much more suited for such simple static queries.
But even a HQL query is useless here, since you simply want to get a bill from its ID. All you need is
Bill bill = (Bill) session.get(Bill.class, billId);
This will get the bill, and since you chose to make the OneToMany association as EAGER, it will also immediately load its bill details.
If you hadn't made the association EAGER (and you should really leave it as LAZY), you could use this simple HQL query to load a bill with its details:
select distinct b from Bill bill
left join fetch bill.billDetails
where bill.id = :billId
Related
Suppose I have some generic tables apple, orange etc and a table note which contains notes about a row in one of my generic table. The note is stored by saving the entity_type (e.g. the table name) and entity_id (e.g. the id of the row).
I'm trying to make a unidirectional One-to-Many mapping from apple to note. Effectively creating this relationship:
SELECT *
FROM apple f
INNER JOIN note n
ON f.id = n.entity_id
AND n.entity_type = 'apple'
I've been trying something like:
#Entity
public class Apple {
...
#OneToMany
#JoinColumn(name = "entity_id", referencedColumnName = "id")
#WhereJoinTable(clause = "entity_type = 'apple'")
private Set<Note> changeNotes = new HashSet<>();
Which isn't working (error is #WhereJoinTable on an association without join table). Any ideas?
Update:
I think this is the sort of thing I"m trying to do https://docs.oracle.com/html/E13946_02/ref_guide_mapping_notes_nonstdjoins.html
However hibernate is looking for a column instead of just using the string...
I have the following situation:
#Entity
public class Period
{
String Name;
}
#Entity
public class Bill
{
Period period;
#OneToMany(mappedBy = "bill", fetch = FetchType.LAZY)
private List<Entry> entry = new ArrayList<Entry>(0);
}
#Entity
public class Entry
{
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "BILL_ID", nullable = false)
Bill bill;
String text;
BigDecimal amount;
}
So what I need is to fetch all the data in a single query, either with the root being the Bill or the Entry using JPA 2.0 criteria (with Hibernate behind). I've read few posts about this problem HERE and HERE and it seems that I can't use subqueries in the result or fetch data two levels deep.
EDIT: To make my problem more clear: When I use Entry as root, I can't fetch Period and when I use Bill as root I can't fetch all other tables in Entry. Also I can't use eager fetch because there are other use cases that need those tables.
Are there any other ways to do this?
Thanks!
To fetch data from association, you use left join fetch clauses:
select distinct b from Bill b
left join fetch b.period
left join fetch b.entry
where b...
or
select distinct e from Entry e
left join fetch e.bill b
left join fetch b.period
where e...
Regarding Criteria, its fetch() method returns a Fetch, which itself has a method fetch() returning a Fetch(), which itself has a method fetch() returning a Fetch, etc. So yes, its supports as many levels you want.
Update: look my answer below on how to check if 2 list intersects (both for #ElementCollection with string/enums and usual entities list mapped like #OneToMany)
I have an entity which contains #ElementCollectionfield with enums.
public enum StatusType {
NEW, PENDING, CLOSED;
}
#Entity
public class MyEntity {
#ElementCollection
#CollectionTable(name = "status_type", joinColumns = {#JoinColumn(name = "my_entity_id")})
#Column(name = "status_type", nullable = false)
private Set<StatusType > statusTypes = new HashSet<StatusType >();
...
}
Now I want to get all entities which contains status NEW or PENDING (or both).
I'm trying to use this query:
SELECT DISTINCT u FROM MyEntity u WHERE u.statusTypes in :statusTypes
But I'm getting exception: org.postgresql.util.PSQLException: No value specified for parameter 9.
How to properly query on collections and filter by intersections?
Problem solved by adding JOIN clause to HQL. Hibernate couldn't implicitly recognize that query needs JOIN clause. May be it will help someone:
SELECT DISTINCT u FROM MyEntity u
LEFT JOIN u.statusTypes statusTypes
WHERE statusTypes in :statusTypes
I set the query params like this:
query.setParameter( "statusTypes", listOfStatusTypesEnums);
It will select rows where at least one element of listOfStatusTypesEnums list is present in entity's statusTypes property (i.e. if 2 list are intersects in some way).
If you have usual list of entities (which are not #ElementCollection, but #OneToMany etc), same rule will work as well. Just use like this: LEFT JOIN u.subEntities subEntities WHERE subEntities.id in :subEntityIds
In my application, user is able to select few items and see the details of all.
I know that I can use the Criteria and using its Restrictions.disjunction(), I can define the
"OR"; however, I need to retrieve the id of selected items from a list which makes it difficult to create the query using criteria.
Criteria cre = session.createCriteria(Category.class,"category");
cre.add(Restrictions.disjunction()) //?????
for(int i=0;i<selection.size();i++){
cre.add(Restrictions.eq("category.items",selection.get(i));
}
....
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#LazyCollection(LazyCollectionOption.FALSE)
public List<CategoryItem> getItems() {
return this.items;
}
Another method is to send separate queries which I reckon thats an inefficient approach.
As Ean mentioned just use the following:
from Category c join c.items i where i.id in :yourList
We have a DB table that is mapped into a hibernate entity. So far everything goes well...
However what we want is to only map enentitys that satisty a specific criteria, like ' distinct(fieldA,fieldB) '...
Is it possible to map with hibernate and hibernate annotations? How can we do it? With #Filter?
I would recommend that you use #Where annotation. This annotation can be used on the element Entity or target entity of a collection. You provide a clause attribute written in sql that will be applied to any select that hibernate performs on that entity. It is very easy to use and very readable.
Here is an example.
#Entity
//I am only interested in Donuts that have NOT been eaten
#Where(clause = "EATEN_YN = 'N'")
public class Donut {
#Column(name = "FILLING")
private String filling;
#Column(name = "GLAZED")
private boolean glazed = true;
#Column(name = "EATEN_YN")
private boolean eaten = false;
...
}
You could create a view and then map that view to entity:
create view my_data as
select ... from ...
#Entity(table="my_data")
public class MyData { ... }
One option is to map the table normally, then you could fetch your always entities through a query or a filter.
You could also make a native SQL query and map the entity on the results:
Query q = sess.createSQLQuery("SELECT DISTINCT fieldA, fieldB FROM some_table")
.addEntity(MyEntity.class);
List<MyEntity> cats = q.list();
It might be also possible to add DISTINCT to this type of HQL query:
select new Family(mother, mate, offspr)
from DomesticCat as mother
join mother.mate as mate
left join mother.kittens as offspr
Methods 1, 3 and 4 will make a read-only mapping.
Could you be more specific about the criteria you are using? The view approach is more generic since you can't do everything with a hibernate query or filter.
perhaps you could create a new Pojo that encapsulates the fields and the condition that they should statisy . And then then make that class a 'custom user defined type', such that Hibernate will have to use the mapping class that you provide, for mapping that 'type'..
In addition to the options mentioned by Juha, you can also create an object directly out of a SQL query using the NamedNativeQuery and SqlResultSetMapping annotations.
#Entity
#SqlResultSetMapping(name = "compositekey", entities =
#EntityResult(entityClass = MiniBar.class,
fields = { #FieldResult(name = "miniBar", column = "BAR_ID"), })
)
#NamedNativeQuery(name = "compositekey",
query = "select BAR_ID from BAR", resultSetMapping = "compositekey")
#Table(name = "BAR")
public class Bar {
Flavor the SQL query to your taste