Java Hibernate #OneToMany Criteria Projections returning NULL - java

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.

Related

Spring Data JPA - Deleting a child in one-to-many relationship

I'm implementing a Spring boot application and using Spring Data JPA in it. As you know you don't have to implement the repository interface for just CRUD methods, because Spring Data JPA creates an implementation on the fly. So I have just this:
public interface PersonRepository extends JpaRepository<Person, Long> {}
I'm working with one-to-many relationship, this is in my Person domain:
#OneToMany(cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY,
mappedBy = "person")
private Set<Contact> contacts = new HashSet<>();
I decided to write an integration test for child removal from the parent:
#Test
public void removeFromContacts() {
// given
Person person = new Person ("test person");
Contact contact = new Contact("test#gmail.com", "+123456789");
contact.setPerson(person);
person.getContacts().add(contact);
personRepository.save(person);
Person savedPerson = personRepository.findOne(person.getId());
Contact persistedContact = savedPerson.getContacts().stream().findFirst().orElse(null);
// when
savedPerson.getContacts().remove(persistedContact);
persistedContact.setPerson(null);
Person edited = personRepository.save(savedPerson);
// then
Assert.assertTrue(edited.getContacts().isEmpty());
}
This test fails. The reason is savedPerson.getContacts().remove(persistedContact) line doesn't change anything, remove method returns false. It's pretty strange, because I'm trying to remove an object from a hash set which has only one object with exact same hash code (equals() method returns true as well). According to this answer the contact object could've been altered somehow after adding it to the hash set. The only thing I can think of is it happened after this line: personRepository.save(person).
If I'm right then I'm really confused: how should I remove the contact from a person, and even if I find a way, is it okay for personRepository.save method to cause a set to malfunction? And if I'm wrong I would love to know the right answer.
Thanks in advance.
Class Compte and Class User joind to one-to-one relationship
public void delete(Integer integer){
User user = userRepository.findOne(integer);
Compte compte = user.getCompte();
compte.setUser(null);
compteRepository.save(compte);
user.setCompte(null);
userRepository.save(user);
compteRepository.delete(compte);
userRepository.delete(user);
}

Java Hibernate temporarily Ignore #ManyToOne annotaion with criteria

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);
....

DAO methods parameters , object-references vs ids

Question
What is the best practice for the type of paramaters of dao/repository method, entity-objects or entity-ids?
Example code
#Entity
class Product {
// ...
#ManyToOne
Seller seller;
}
#Entity
class Seller {
#Id #GeneratedValue
Long id;
}
class ProductDao {
// ...
// Using ids
public List<Product> getProductsOf(long sellerId) {
return getSession()
.createQuery("from Product where seller.id = ?")
.setLong(0, sellerId)
.list();
}
// Using object-references
public List<Product> getProductsOf(Seller seller) {
return getSession()
.createQuery("from Product where seller = ?")
.setEntity(0, seller)
.list();
}
// Using object-references using merge() on a detached object
public List<Product> getProductsOf2(Seller seller) {
Seller persistentSeller = getSession().merge(seller);
return getSession()
.createQuery("from Product where seller = ?")
.setEntity(0, seller)
.list();
}
// Using object-references using lock() on a detached object
public List<Product> getProductsOf3(Seller seller) {
getSession().buildLockRequest(LockOptions.NONE).lock(seller);
return getSession()
.createQuery("from Product where seller = ?")
.setEntity(0, seller)
.list();
}
}
Pros and cons
I have found the following pros and cons, but I was wondering if there is a best practice among experienced Spring/Hibernate/JPA users.
Pros of: getProductsOf(Seller seller)
Easy to use from a client perspective when you already have a seller that is in the persistent context (persistent state).
Cons of: getProductsOf(Seller seller)
You have to verify that seller is in persistent or detached state, which can make its implementation verbose. You'll have to use merge() or locking, see getProductsOf2() and getProductsOf3().
Even if you know the id of the seller, you first have to query the seller object separatly. (load() can be used to use a proxy instead to avoid the extra query to Seller, but you still have to call the session object.)
the parameter can be null.
Pros of: getProductsOf(long sellerId)
When you don't have a seller object yet, but know the sellerId, this may be faster when you only need to query for a sellerId once in the unit-of-work.
Avoids the null reference problems
Cons of: getProductsOf(long sellerId)
When multiple "long" parameters exist in the method, you may mistake in the argument call order, causing you to query using wrong ids.
Feels like a less object-oriented approach than using an object as parameter.
The method call looks less clean:
getProductsOf(seller.getId())
instead of:
getProductsOf(seller)
My preference
I'm using getProductsOf(Seller seller), but having to verify whether seller is in persistent or detached state is very cumbersome. Therefor, I'm thinking of using ids instead.
The best way is to avoid writing down your own DAO and use Spring Data instead.
I prefer the Spring Repository API, which looks like this:
public interface CrudRepository<T, ID extends Serializable>
extends Repository<T, ID> {
<S extends T> S save(S entity);
T findOne(ID primaryKey);
Iterable<T> findAll();
Long count();
void delete(T entity);
boolean exists(ID primaryKey);
}
the save and delete methods take an entity
the findOne and exists take an identifier because it assumes you don't have the entity that you want to fetch
As for findOne, it's better to have it take an identifier. This way you can call it even if you have an entity. If it were taken an entity, then you'd have to create a transient entity with a populated identifier just for the sake of fetching the associated managed entity.
Why not have them both?
public List<Product> getProductsOf(long sellerId){
return getSession()
.createQuery("from Product where seller.id = ?")
.setLong(0, sellerId)
.list();
}
public List<Product> getProductsOf(Seller seller){
return getProductsOf(seller.getId());
}
On a side note, I prefer to use classes instead of native types for ids because that way you can verify if the object is new (seller.getId()==null) and call either persist() or merge().

Getting abstract superclass mapped by a View using Hibernate returns Invalid column name

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.

Hibernate #ManyToOne getId() causes fetch

I have the Problem that a quite simple select (SELECT h FROM Hero h where h.owner = :player) causes a n+1 Problem. The query triggers the select to the game for each hero entity.
First i added fetch type lazy which removed the alternative queries during the select. In my code i need the game only once to get the id. This triggered the select again for every entity.
So i added a join fetch which helped, BUT it causes a join i don't need! How can i tell the hibernate proxy object to give me the id without fetching the whole entity?
I tried the tips there without success: http://256stuff.com/gray/docs/misc/hibernate_lazy_field_access_annotations.shtml
Both #AccessType from hibernate and #Access from javax make no difference. The game will always be fetched when i call getId().
Any Ideas what i am missing? I would need this quite often and i would like to avoid joins if i can.
greetings,
markus
PS: I use jpa2 + hibernate 4 with jboss 7.
#Entity
#NamedQueries({
#NamedQuery(name = "Hero.findByPlayer", query = "SELECT h FROM Hero h JOIN FETCH h.game where h.owner = :player")
})
public class Hero extends GameCharacter implements Serializable {
#ManyToOne
private Player owner;
#Entity
public abstract class GameCharacter extends GameObject implements Serializable {
... nothing special in here
}
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class GameObject implements Serializable {
#Id
private String id = java.util.UUID.randomUUID().toString();
#ManyToOne(fetch=FetchType.LAZY)
protected Game game;
#Entity
public class Game implements Serializable {
private static final long serialVersionUID = 4379242677193301727L;
#Id
private String id = java.util.UUID.randomUUID().toString();
This is just a side affect of the way lazy loading in hibernate works. Essentially, any access of the lazy object will cause it to populate. It doesn't make a special case of the id.
I don't think you're actually going to be able to access the ID from the game object without triggering the loading. What you can do is ask hibernate for the id of an object using the getIdentifier method. I believe this will not trigger the fetch as hibernate is simply looking up the metadata it has for the object.
Alternatively you can load the game id alongsite the hero when executing your query.
E.g.
SELECT h, h.game.id FROM Hero h where h.owner = :player
Rather than finding you a list of heros as your current query does, this will return a list of pairs, each pair having the hero and the game id.
ID is treated specially in HQL so this shouldn't trigger the fetch or join you're getting when trying to access the object.

Categories

Resources