English 中文(简体)
How do I implement toString() in a class that is mapped with Hibernate?
原标题:

I have an instance of a class that I got from a Hibernate session. That session is long gone. Now, I m calling toString() and I m getting the expected LazyInitializationException: could not initialize proxy - no Session since I m trying to access a reference which Hibernate didn t resolve during loading of the instance (lazy loading).

I don t really want to make the loading eager since it would change the query from about 120 characters to over 4KB (with eight joins). And I don t have to: All I want to display in toString() is the ID of the referenced object; i.e. something that Hibernate needs to know at this point in time (or it couldn t do the lazy loading).

So my question: How do you handle this case? Never try to use references in toString()? Or do you call toString() in the loading code just in case? Or is there some utility function in Hibernate which will return something useful when I pass it a reference which might be lazy? Or do you avoid references in toString() altogether?

最佳回答

It s possible to do this by setting the accesstype of the ID field to "property". like:

@Entity
public class Foo {
    // the id field is set to be property accessed
    @Id @GeneratedValue @AccessType("property")
    private long id;
    // other fields can use the field access type
    @Column private String stuff;
    public long getId() { return id; }
    public void setId(long id) { this.id = id; }
    String getStuff() { return stuff; }
    // NOTE: we don t need a setStuff method
}

It s explained here. This way the id field is allways populated when a proxy is created.

问题回答

I ve found a workaround:

public static String getId (DBObject dbo)
{
    if (dbo == null)
        return "null";

    if (dbo instanceof HibernateProxy)
    {
        HibernateProxy proxy = (HibernateProxy)dbo;
        LazyInitializer li = proxy.getHibernateLazyInitializer();
        return li.getIdentifier ().toString ();
    }

    try
    {
        return Long.toString (dbo.id ());
    }
    catch (RuntimeException e)
    {
        return "???";
    }
}

So what this code does is it fetches the ID (a 64bit number) from the object. DBObject is an interface which defines long id(). If the object is a Hibernate proxy, then I talk to its LazyInitializer to get the ID. Otherwise, I call id(). Usage:

class Parent {
    DBObject child;
    public String toString () {
        return "Parent (id=..., child=" + getId(child)+")");
    }
}

I ve found the way that best fits good practice is a modification of the solution found on this blog: http://www.nonfunc.com/2016/02/05/jpa-performance-gotcha-tostring-really/. It needed modification for nullable fields and for Collections objects.

public toString() {
  return String.format("FuBar [id=%d" +  
      + ", fu=%s" // fu is a lazy non-nullable field
      + ", bar=%s" // bar is a nullable lazy field
      + ", borks=%s]", // borks is a lazy collection of Bork objects
      id,
      fu instanceof HibernateProxy ? "[null]" : fu.toString(),
      bar == null || bar instanceof HibernateProxy ? "[null]" : bar.toString(),
      borks instanceof PersistentSet ? "[null]" : borks.toString());
}

If all you want to return is the ID of the object, I imagine calling getID(), then parse the int/long as a String value at the moment you want it displayed would work just fine. At least that s how it seems based on the question.

EDIT

How to solve the LazyInitializationException using JPA and Hibernate

After viewing the comment and doing some searching I believe this may be most beneficial to your scenario.





相关问题
Multiple Hibernate instances using C3P0

I am facing a weird problem and it seems to be c3p0 related. I am starting two instances of an app in the same java vm which interact with each other. After some operations "APPARENT DEADLOCK" ...

Hibernate vs Ibatis caching

We can speed up a hibernate app easyly with 2nd level cache using infinispan or ehcache/terracotta,... but ibatis only have a simple interface to implement for caching. And hibernate knows more ...

Using annotations to implement a static join in hibernate

I m relatively new to hibernate and was wondering if someone could help me out. While I have no issues implementing a normal join on multiple columns in hibernate using the @JoinColumns tag, I m ...

Hibernate query with fetch question

I have a 2 entities in a One-To-Many relationship: OfficeView.java: public class OfficeView implements java.io.Serializable { private Integer officeId; private String addr1; private ...

hibernate interceptors : afterTransactionCompletion

I wrote a Hibernate interceptor : public class MyInterceptor extends EmptyInterceptor { private boolean isCanal=false; public boolean onSave(Object entity, Serializable arg1, Object[] arg2, String[]...

How to prevent JPA from rolling back transaction?

Methods invoked: 1. Struts Action 2. Service class method (annotated by @Transactional) 3. Xfire webservice call Everything including struts (DelegatingActionProxy) and transactions is configured ...

Hibernate/GORM: collection was not processed by flush()

I have an integration test in my Grails application that fails when I try to save an entity of type Member invitingMember.save(flush: true) This raises the following exception org.hibernate....

Hibernate Criteria API equivalent for "elements()"

Is it possible to implement the following query using Criteria API? select order from ORDER as order,ITEM as item where item.itemID like ITM_01 and item in elements(order.items)

热门标签