I have a Hibernate query with Criteria.
What I would like to do is (just for one query) tell hibernate to ignore an existing #ManyToOne annotation.
that is because hibernate creates and Left join on other tables.
I could figure it how to do it.
I have found this 2 links which didn't solve my problem:
Hibernate: How to remove an entity to which none refers to anymore in ManyToOne?
What is the difference between DELETE_ORPHAN and DELETE?
If you have such mapping:
//Parent
public class A {
...
}
//Child
public class B {
private A parent; //Many to one
...
}
Please try something like this:
Criteria q = ....;
q.setFetchMode("parent", FetchMode.SELECT);
....
Related
The situation is as following. Say I've got a Kid, and I want to get his Parent. The abstract Parent is situated in a View. The Parent can either be a Mother or a Father. The Mother is also defined in a View.
#Entity
public class Kid extends DomainObject {
private IParent theParent;
#ManyToOne(fetch = FetchType.LAZY, targetEntity = Parent.class)
#JoinColumn(name = "TheParentId")
public IParent getTheParent() {
return theParent;
}
#Override
public void setTheParent(IParent theParent) {
this.theParent = theParent;
}
}
#Entity
#Inheritance(strategy= InheritanceType.JOINED)
#Table(name = "Parent")
public abstract class Parent {
}
#Entity
public class Mother extends Parent {
}
So, using Hibernate, I try to retrieve the Mother-object by calling getTheParent() on Kid:
from Kid hobj left join fetch hobj.theParent pa
This works fine in the database. But when running this via Hibernate, it returns SQL exception: Invalid column name(UNKNOWN)
There are a few pointers which can be the cause. In the old database, Mother and Father were Table's instead of Views. My guess is that Hibernate understood the link because of foreign keys. Changing the Parent from Table to View broke the application. But searching around points out that Hibernate treats View's and Table's equally (to some extent). Why does getting the exact query being used by Hibernate work when entered directly, but not when using Hibernate?
The problem seemed to be in the select-clause of the query. When adding multiple objects to the select column (running deeper with more tables then Kid, Mother and Father), Hibernate would get confused. When I only used the Kid-object (and fill up items using Kid.getX().getY().getZ()... ), Hibernate had no problem fetching everything.
Seems to be a bug in Hibernate.
I have One to many relationship Owner->Dog.
I am to query the dog by ID as well bring the Owner in EAGER way I have set this code using Hibernate 4.1.6 not XML mapping is used. i only need some fields from DOG and OWNER using Projections
the SQL being generated by Hibernate is perfect but my objects is not being populate because DOG is returning the fields populated but owner is returned DOG.OWNER==NULL here is the code i am using so far...
My entities.other code is omit by brevity
#Entity
public class Owner implements Serializable
{
Set<Dog>dogs=new HashSet<Dogs>(0);
#OneToMany(fetch=FetchType.LAZY, mappedBy="owner")
public Set<Dogs> getDogs(){return this.dogs}
}
#Entity
public class Dog implements Serializable
{
private Owner owner;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="ownerid")
public Owner getOwner(){return this.owner;}
}
here is my method.
public Dog getDogAndOwnerById(Integer dogId)
{
Projection p=Projections.projectionList()
.add(Projections.property("d.id"),"id")
.add(Projections.property("o.id"),"id");//and others fields
Session session = getHibernateTemplate().getSessionFactory().openSession();
Criteria like = session.createCriteria(Dog.class,"d")
.add(Restrictions.idEq(dogId)).setProjection(p)
.setResultTransformer(Transformers.aliasToBean(Dog.class))
.setFetchMode("owner",FetchMode.JOIN).createAlias("owner","o");
Dog dog = (Dog)like.uniqueResult();
//Object[]obj=(Object[])like.uniqueResult(); for(Object id:obj)System.out.println(id);
//System.out.println(obj.length);
session.close();
return dog;
//dog is OK BUT dog.OWNER is null.
}
the query is perfect here is the SQL
select
this_.ID as y0_,
owner_.ID as y1_
from
dog this_
inner join
owner owner_
on this_.ownerid=owner_.ID
where
and this_.ID = ?
my problem is... Dog instance is NOT null and all the fields are O.K meanwhile Dog.Owner is returnig null I have try this not using any Transformers.
Object[]obj=(Object[])like.uniqueResult(); for(Object id:obj)System.out.println(id);
System.out.println(obj.length);
And I can see the data correct what Hibernate is not returning my objects right? What I am doing wrong.
any help is hugely appreciate.
[update]
if i use this
Projection p=Projections.projectionList()
.add(Projections.property("d.id"),"id")
.add(Projections.property("o.status"),"status");
and status belongs to both tables the DOG entity is populate the other is not.
if i use
Projection p=Projections.projectionList()
.add(Projections.property("d.id"),"id")
.add(Projections.property("o.address"),"address");
and adress belong only to owner exception is thrown.
Exception in thread "main" org.hibernate.PropertyNotFoundException:
Could not find setter for address on class com.generic.model.Dog
Seems that Hibernate ALWAYS return at maximun 1 entity populate they can't populate both tables[selected columns] into objects[selected objects]?
I wrote a ResultTransformer that can solve your problem. It's name is AliasToBeanNestedResultTransformer, check it out on github.
i follow this post Complex Hibernate Projections and as result i write my own Transformer because resultTransformer alias to bean in hibernate in one level deep.
here is my simple resultTransformer
public class MyOwnTransformer implements ResultTransformer
{
#Override//the same order in projection list properties is the same returned by data array...
public Dog transformTuple(Object[]data,String[]alias)
{return new Dog((Integer)data[0],new Owner((Integer)data[1]));}
#Override
public List transformList(List dogs){return dogs;}//nothing to do here....
}
and in my criteria i fix the code like this.
public Dog getDogAndOwnerById(Integer dogId)
{
Projection p=Projections.projectionList()
.add(Projections.property("d.id"))//i dont need the alias anymore..
.add(Projections.property("o.id"));
Session session = getHibernateTemplate().getSessionFactory().openSession();
Criteria like = session.createCriteria(Dog.class,"d")
.add(Restrictions.idEq(dogId)).setProjection(p)
.setResultTransformer(new MyOwnTransformer())
.setFetchMode("owner",FetchMode.JOIN).createAlias("owner","o");
Dog dog = (Dog)like.uniqueResult();
session.close();
return dog;
}
i hope it helps somebody.
Suppose I have 2 JPA entities:
#Entity
public class OwnerEntity {
private List<OwnedEntity> subEntities
// ...
}
#Entity
public class OwnedEntity {
private String quasiUniqueSid;
private OwnerEntity ownerEntity
// ...
}
As you can see they have a many to one relationship: an OwnerEntity can have many OwnedEntitys.
What I want to achieve is to assign each OwnedEntity a unique sid based on its owner. So I can have for example 2 owned entities with the same quasiUniqueSid but they cannot have the same owner. Do Hibernate has some built-in functionality for this kind of problem? I can remember other ORMs (not Java related) which could do this thus my question. I'm using the latest Hibernate version (4.1.8)
It seems you need a composite key, like this:
#Entity
#Table(uniqueConstraints=#UniqueConstraint(columnNames={"quasiUniqueSid","ownerEntity_id"}), name="myUniqueConstraint")
public class OwnedEntity {
...
String quasiUniqueSid;
#ManyToOne
OwnerEntity ownerEntity;
...
}
A full documentation you can find here.
If you wanna explicitly define the column name for ownerEntity, you can use:
#JoinColumn(name="ownerEntity_id")
I'm having some issues getting a bidirectional one-to-many association working with JoinTables. This is what I got:
Class A:
#OneToMany
#JoinTable(name="join_table",
JoinColumns={#JoinColumn(name="a_id")},
inverseJoinColumns={#JoinColumn(name="b_id")}
)
#Cascade(org.hibernate.annotations.CascadeType.ALL)
public Set<B> getBs() {
return bs;
}
Class B:
#ManyToOne
#JoinTable(name="join_table",
joinColumns={#JoinColumn(name="b_id", insertable=false,updatable=false)},
inverseJoinColumns={#JoinColumn(name="a_id", insertable=false,updatable=false)})
public A getA() {
return a;
}
If I create a instance of A and B, add the instance of B to A and save. It works. But when I reload the instance of A and try and access the set of Bs it throws a LazyInitializationError with the message "illegal access to loading collection ".
Where am I going wrong here? :) Can anybody point me to a example of bidirectional association which uses a join table. And where the ownership is kept to Class A, I have searched though the documentation at hibernate.org but I cant seem to find it.
-Daniel
Your mapping are proper and that's why the entry is getting saved in the Database. The issue in fetching is because of the Lazy Initialization.
To solve it modify mapping of the class A as,
#OneToMany(fetch=FetchType.LAZY)
#JoinTable(name="join_table",
joinColumns={#JoinColumn(name="a_id")},
inverseJoinColumns={#JoinColumn(name="b_id")}
)
#Cascade(org.hibernate.annotations.CascadeType.ALL)
public Set<B> getBs() {
return bs;
}
This will fire an additional query to the table B and initialize the collection. It might affect the performance depending on the no of entries in your defendant table.
Read the API here for more information.
Hi I have two classes like this:
public class Indicator implements Serializable {
...
#OneToMany(mappedBy = "indicator",fetch=FetchType.LAZY)
private List<IndicatorAlternateLabel> indicatorAlternateLabels;
public List<IndicatorAlternateLabel> getIndicatorAlternateLabels() {
return indicatorAlternateLabels;
}
public void setIndicatorAlternateLabels(List<IndicatorAlternateLabel> indicatorAlternateLabels) {
this.indicatorAlternateLabels = indicatorAlternateLabels;
}
...
}
public class IndicatorAlternateLabel implements Serializable {
...
#ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
#JoinColumn(name = "IndicatorID")
#XmlTransient
private Indicator indicator;
...
}
When I use them like this:
public MetricTypeDetail getMetricTypeDetail(Integer metricTypeId) {
Criteria crit = sessionFactory.getCurrentSession().createCriteria(Indicator.class, "sub")
.add(Restrictions.eq("number", metricTypeId))
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).setCacheable(true);
crit.setMaxResults(1);
Indicator indicator=(Indicator) crit.uniqueResult();
MetricTypeDetail metricTypeDetail=new MetricTypeDetail(indicator);
List<IndicatorAlternateLabel> indicatorAlternateLabels = null;
indicatorAlternateLabels=indicator.getIndicatorAlternateLabels();
metricTypeDetail.setIndicatorAlternateLabels(indicatorAlternateLabels);
return metricTypeDetail;
}
This code returns an exception:
failed to lazily initialize a collection of role: com.porism.service.domain.Indicator.indicatorAlternateLabels, no session or session was closed
Any idea? I'm very new to Hibernate
Lazy exceptions occur when you fetch an object typically containing a collection which is lazily loaded, and try to access that collection.
You can avoid this problem by
accessing the lazy collection within a transaction.
Initalizing the collection using Hibernate.initialize(obj);
Fetch the collection in another transaction
Use Fetch profiles to select lazy/non-lazy fetching runtime
Set fetch to non-lazy (which is generally not recommended)
Further I would recommend looking at the related links to your right where this question has been answered many times before. Also see Hibernate lazy-load application design.
It's possible that you're not fetching the Joined Set. Be sure to include the set in your HQL:
public List<Node> getAll() {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("FROM Node as n LEFT JOIN FETCH n.nodeValues LEFT JOIN FETCH n.nodeStats");
return query.list();
}
Where your class has 2 sets like:
public class Node implements Serializable {
#OneToMany(fetch=FetchType.LAZY)
private Set<NodeValue> nodeValues;
#OneToMany(fetch=FetchType.LAZY)
private Set<NodeStat> nodeStats;
}
Try swich fetchType from LAZY to EAGER
...
#OneToMany(fetch=FetchType.EAGER)
private Set<NodeValue> nodeValues;
...
But in this case your app will fetch data from DB anyway.
If this query very hard - this may impact on performance.
More here:
https://docs.oracle.com/javaee/6/api/javax/persistence/FetchType.html
==> 73
as suggested here solving the famous LazyInitializationException is one of the following methods:
(1) Use Hibernate.initialize
Hibernate.initialize(topics.getComments());
(2) Use JOIN FETCH
You can use the JOIN FETCH syntax in your JPQL to explicitly fetch the child collection out. This is somehow like EAGER fetching.
(3) Use OpenSessionInViewFilter
LazyInitializationException often occurs in the view layer. If you use Spring framework, you can use OpenSessionInViewFilter. However, I do not suggest you to do so. It may leads to a performance issue if not used correctly.