Циклическая сериализация с отношением «многие ко многим» с Hibernate - PullRequest
1 голос
/ 08 февраля 2010

У меня есть родительское (Program) пожо, имеющее отношения многие ко многим со своими детьми (подписчик).

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

ERD выглядит так: Программа <-> Абонент

Это означает, что то, что было возвращено крошечным блоком данных (json) размером 17 КБ, стало возвращением 6,9 МБ. Таким образом, в свою очередь, уходит время на сериализацию данных, а затем возвращает их.

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

(Примечание. Ранее я пытался добавить столько ленивых аннотаций, сколько смогу найти, просто чтобы посмотреть, помогает ли это. Это не так. Возможно, я тоже поступаю неправильно?)

Program.java

@Entity
@Table(name="programs")
public class Program extends Core implements Serializable, Cloneable {
   ...
   @ManyToMany()
   @JoinTable(name="program_subscribers",
         joinColumns={@JoinColumn(name="program_uid")},
         inverseJoinColumns={@JoinColumn(name="subscriber_uid")})
   public Set<Subscriber> getSubscribers() { return subscribers; }
   public void setSubscribers(Set<Subscriber> subscribers) { this.subscribers = subscribers; }

Subscriber.java

@Entity
@Table(name="subscribers")
public class Subscriber extends Core implements Serializable {
   ...
   @ManyToMany(mappedBy="subscribers")
   public Set<Program> getPrograms() { return programs; }
   public void setPrograms(Set<Program> programs) { this.programs = programs; 

}

Осуществление

public Collection<Program> list() {
  return new Programs.findAll();
}

Ответы [ 4 ]

3 голосов
/ 08 февраля 2010

Вы не упомянули фреймворк, который вы используете для сериализации JSON, поэтому я предполагаю, что JAXB. В любом случае, идея состоит в том, чтобы каким-то образом сделать Subscriber.getPrograms(..) переходным, чтобы он не сериализовался. Hibernate заботится об этих «петлях», а другие нет. Итак:

@XmlTransient
@ManyToMany(..)
public Set<Program> getPrograms()...

Если вы используете другую платформу, она может иметь другую аннотацию / конфигурацию для указания переходных полей. Как и ключевое слово transient.

Другой способ - настроить маппер так, чтобы он обрабатывал цикл вручную, но это утомительно.

1 голос
/ 14 августа 2010

Как насчет использования аннотаций? http://thinkinginsoftware.blogspot.com/2010/08/json-and-cyclical-references.html

1 голос
/ 08 февраля 2010

1) Как работает "ваша" сериализация. Я имею в виду, это JAXB или пользовательская сериализация или что-то еще. 2) Практически все фреймворки позволяют устанавливать глубину сериализации. Я имею в виду, вы можете установить, например, глубину в 2. 3) Я советую вам не сериализовать объект с детьми, пометить их (childre) как временные и сериализовать отдельно.

0 голосов
/ 09 февраля 2010

И Божо, и Понкин находятся на правильном пути. Мне нужно было прекратить сериализацию данных по сети, но большая проблема в том, что я не могу изменить класс / метод pojo -> toJSON, где происходит сериализация. Я также беспокоился о том, чтобы тратить время на метод toJSON (), учитывая, что в момент сериализации я столкнулся с таким падением производительности, что мне нужно исправление, которое произойдет до того, как у меня будут данные, а не после.

Кроме того, из-за характера двунаправленного дизайна «многие ко многим», который я перечислил, у меня всегда будет эта проблема циклических программ / подписчиков / программ / ....

Разрешение: (пока, по крайней мере) Я удалил метод Subscriber.getProgram () и создал метод поиска в ProgramDAO, который возвращает Программы по подписчику.

public List<Program> findBySubscriber(Subscriber subscriber) {
  String hql = "select p " +
     "from Program p " +
     " join p.subscribers s " +
     "where s = :sub"
     ;    

  Query q = getSession().createQuery(hql);
  q.setEntity("sub", subscriber);

  List<Program> l = q.list();
  return l;
}

Для любой CRUD-работы, я думаю, мне просто придется зацикливаться на Programs.getSubscribeers или писать больше вспомогательных методов hql.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...