При преобразовании проекта из Ibatis в JPA 2.1 я столкнулся с проблемой, когда мне приходится загружать полный графический объект для набора объектов, не ударяя N + 1, выбирая или используя декартовы продукты по соображениям производительности.
Пользовательский запрос даст List <Task> , и мне нужно убедиться, что когда я возвращаю задачи, у них есть все свойства, включая parent, children, зависимости и свойства. Сначала позвольте мне объяснить два объекта объекта.
Задача является частью иерархии. Он может иметь родительскую задачу, и у нее также могут быть дети. Задача может зависеть от других задач, выражаемых свойством "зависимости". Задача может иметь много свойств, выражаемых свойством properties.
Примеры объектов были максимально упрощены, и код шаблона удален.
@Entity
public class Task {
@Id
private Long id;
@ManyToOne(fetch = LAZY)
private Task parent;
@ManyToOne(fetch = LAZY)
private Task root;
@OneToMany(mappedBy = "task")
private List<TaskProperty> properties;
@ManyToMany
@JoinTable(name = "task_dependency", inverseJoinColumns = { @JoinColumn(name = "depends_on")})
private List<Task> dependencies;
@OneToMany(mappedBy = "parent")
private List<Task> children;
}
@Entity
public class TaskPropertyValue {
@Id
private Long id;
@ManyToOne(fetch = LAZY)
private Task task;
private String name;
private String value;
}
Иерархия задач для заданной задачи может быть бесконечно глубокой, поэтому для упрощения получения всего графика задача будет иметь указатель на ее корневую задачу с помощью свойства "root".
В Ibatis я просто взял все Задачи для отдельного списка корневых идентификаторов, а затем сделал ad-hoc-запросы для всех свойств и зависимостей с запросом "task_id IN()". Когда у меня были такие, я использовал Java-код для добавления свойств, дочерних элементов и зависимостей ко всем объектам модели, чтобы график был завершен. Для любого списка задач по размеру я бы тогда сделал только 3 SQL-запроса, и я пытаюсь сделать то же самое с JPA. Поскольку свойство "parent" указывает, где добавить дочерние элементы, мне даже не пришлось запрашивать их.
Я пробовал разные подходы, в том числе:
Пусть ленивая загрузка сделает это
- Эксплуатационное самоубийство, не нужно уточнять:)
ПРИСОЕДИНЯЙТЕСЬ ПОЛЬЗОВАТЕЛЕЙ, ПРИСОЕДИНЯЙТЕСЬ НА FETCH, НАПРАВЛЯЙТЕ НАСТРОЙКИ FETCH
- Это проблематично, потому что полученные декартовы продукты огромны, и моя реализация JPA (Hibernate) не поддерживает List, только Set при наборе нескольких пакетов. Задача может иметь огромное количество свойств, что делает декартовы продукты неэффективными.
Запросы ad-hoc так же, как и в ibatis
- Я не могу добавить дочерние элементы, зависимости и свойства к Lazy инициализированным коллекциям объектов Task, потому что Hibernate затем попытается добавить их в качестве новых объектов.
Одним из возможных решений может быть создание новых объектов Task, которые не управляются JPA, и сшить мою иерархию вместе с ними, и я думаю, что я могу жить с этим, но это не очень "JPA", а затем я не может использовать JPA для того, что хорошо подходит для отслеживания и сохранения изменений в моих объектах автоматически.
Любые подсказки будут очень признательны. Я открыт для использования специальных расширений поставщика, если это необходимо. Я работаю в Wildfly 8.1.0.Final(полный профиль Java EE7) с Hibernate 4.3.5.Final.