3

I've implemented equals()/hashCode() methods as suggested in an older topic on stackoverflow. The problem of that approach is the exception

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:160) [hibernate-core-4.1.6.Final.jar:4.1.6.Final]
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:259) [hibernate-core-4.1.6.Final.jar:4.1.6.Final]
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185) [hibernate-core-4.1.6.Final.jar:4.1.6.Final]
    at pkg.db.TblChain_$$_javassist_815.equals(TblChain_$$_javassist_815.java) [classes:]
    [...]

which is thrown BEFORE equals() is invoked. It only happens, when the entity has e.g. foreign keys to other entities. Hibernate tries to fetch those entities and triggers the exception because of the closed session (equals() is invoked in a new JSF request, EntityManager is request scoped).

The guy of the solution never hit that problem that's why I'm asking you for help.

Edit 14.04.2015 14:50: Both equals() are implemented using the ID of the entity. But for this example I've replaced its implementations with a simple return, as it doesn't matter. I've found out that it doesn't matter if I have another foreign entity (e.g. tblChainType) in the foreign entity (tblChain). It will always fail, if the first one was not used while the entity manager, that was used for loading, was active.

// Entity classes
public class TblChainInstance {
    private TblChain tblChain; // Foreign entity

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "intChainId", nullable = false)
    public TblChain getTblChain() {
        return this.tblChain;
    }

    public boolean equals(Object other) {
        return false; // doesn't matter, what I have here. 
                      // It always works if this is the selected Entity.
    }
}

public class TblChain {
    public boolean equals(Object other) {
        return false; // doesn't matter, what I have here. 
                      // It always throws a LazyInitializationException
    }
}

// Testcode
@Named @ViewScoped
public class MyBean implements Serializable {
    private TblChainInstance _tblChainInstance;

    @PostConstruct
    public void _init() {
        _tblChainInstance = new JPAQuery(_entityManager).from(qtChainInstance)
            .limit(1).singleResult(qtChainInstance);
    }

    public void actionListener() {
        System.out.println(_tblChainInstance.equals(1)); // outputs false
        System.out.println(_tblChainInstance.getTblChain().equals(1)); // throws
    }
}
Community
  • 1
  • 1
grubi
  • 155
  • 2
  • 16

2 Answers2

1

Hope I am able to understand your issue.

Either avoid lazy loading and make it compulsory which will fetch results during the same query fire OR modify your equals and hashcode method

Hope these help (suggested way of writing the methods in case of foreign key relations)
Should I write equals methods in JPA entities
https://developer.jboss.org/wiki/EqualsandHashCode

Emil Sierżęga
  • 1,785
  • 2
  • 31
  • 38
Godwin
  • 512
  • 4
  • 14
  • @MasterSlave The problem is, that the *equals()* method is not entered at all. Hibernate throws the exception before my implementation of the method is really accessed. I could change it to returning any fixed value and it stills throws the exception. I will extend my initial posting to give you a better example. – grubi Apr 14 '15 at 13:06
1

To complement on @Godwin's answer, I would change the equals and hashCode, so that they are reliable in both the case where the object is attached to the persistent context as well as when its detached. This means that you should avoid any associated objects, or the auto generated Id. The link that @Godwin provided explains it all, the summary of it is that you should try to find a natural key, (e.g. an email in a User entity or the like)

One thing that you should not do is change to EAGER loading on account of this, 'cause there's a well known hibernate bug, where hashCode is triggered before the field values are populated leading to even bigger mess

Master Slave
  • 27,771
  • 4
  • 57
  • 55