Как я могу реализовать toString () в классе, который сопоставлен с Hibernate? - PullRequest
6 голосов
/ 12 ноября 2009

У меня есть экземпляр класса, который я получил из сеанса Hibernate. Эта сессия давно прошла. Теперь я звоню toString() и получаю ожидаемое LazyInitializationException: could not initialize proxy - no Session, так как пытаюсь получить доступ к ссылке, которую Hibernate не разрешил во время загрузки экземпляра (отложенная загрузка).

Я не хочу делать загрузку энергичной, так как запрос изменится с 120 символов до более 4 КБ (с восемью объединениями). И мне не нужно: все, что я хочу отобразить в toString(), это идентификатор объекта, на который есть ссылка; то есть что-то, что Hibernate должен знать в данный момент (или он не может выполнять ленивую загрузку).

Итак, мой вопрос: как вы справляетесь с этим делом? Никогда не пытайтесь использовать ссылки в toString()? Или на всякий случай звоните toString() в коде загрузки? Или в Hibernate есть какая-то служебная функция, которая будет возвращать что-то полезное, когда я передаю ей ссылку, которая может быть ленивой? Или вы вообще избегаете ссылок на toString()? 1013 *

Ответы [ 4 ]

5 голосов
/ 12 ноября 2009

Это можно сделать, установив для accesstype поля ID значение «свойство». как:

@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
}

Это объяснено здесь . Таким образом, поле id всегда заполняется при создании прокси.

1 голос
/ 01 июня 2017

Я нашел способ, который лучше всего подходит для хорошей практики, - это модификация решения, найденного в этом блоге: http://www.nonfunc.com/2016/02/05/jpa-performance-gotcha-tostring-really/. Требуется модификация для полей, допускающих обнуляемость, и для объектов Коллекции.

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]" : bar.toString(),
      bar == null || bar instanceof HibernateProxy ? "[null]" : bar.toString(),
      borks instanceof PersistentSet ? "[null]" : borks.toString());
}
1 голос
/ 12 ноября 2009

Я нашел обходной путь:

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 "???";
    }
}

Итак, этот код выполняет выборку идентификатора (64-битного числа) из объекта. DBObject - это интерфейс, который определяет long id(). Если объект является прокси Hibernate, тогда я говорю с LazyInitializer, чтобы получить идентификатор. В противном случае я звоню id(). Использование:

class Parent {
    DBObject child;
    public String toString () {
        return "Parent (id=..., child=" + getId(child)+")");
    }
}
0 голосов
/ 12 ноября 2009

Если все, что вы хотите вернуть, это идентификатор объекта, я представляю вызов getID (), а затем анализируем int / long как значение String в тот момент, когда вы хотите, чтобы оно отображалось, работало бы просто отлично. По крайней мере, так кажется на основании вопроса.

EDIT

Как решить LazyInitializationException, используя JPA и Hibernate

После просмотра комментария и некоторых поисков я считаю, что это может быть наиболее полезным для вашего сценария.

...