Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / JPA @NamedQuery + @NamedEntityGraph / 16 сообщений из 16, страница 1 из 1
11.09.2017, 13:11
    #39519125
Лысый дядька
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Добрый день. Экспериментирую с JPA (Hibernate) и столкнулся с поведением, которое я не могу классифицировать: либо я действую в правильном направлении, но делаю неправильно, либо я пытаюсь делать то, что никто не делает, либо это косяк хибернейта.
У меня есть несколько связанных различными видами отношений моделей. Для того, чтобы минимизировать количество запросов при получении объекта со всеми связями я не нашел более удачного решения, чем использовать EntityGraph (если есть другое решение прошу показать пальцем). Этот механизм великолепно работает, но только до тех пор, пока я не пытаюсь сделать NamedQuery, который бы использовал этот граф. Он просто отрабатывает, как будто никакой хинт в запрос не передается.

Вот модели
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
@Entity
public class Department {

    @Id
    @GeneratedValue
    private long id;

    private String name;

    @OneToMany(mappedBy = "department")
    private List<Person> persons;

    @OneToOne
    private DepartmentType type;

    @Override
    public String toString() {
        return "Department id=" + this.id + " " + this.name;
    }

    // region getters

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Person> getPersons() {
        return persons;
    }

    public void setPersons(List<Person> persons) {
        this.persons = persons;
    }

    public DepartmentType getType() {
        return type;
    }

    public void setType(DepartmentType type) {
        this.type = type;
    }

    // endregion
}


@Entity
@NamedEntityGraph(name="departnemtsTypesWithDepartments", attributeNodes={@NamedAttributeNode("department")})
@NamedQuery(name = "departmetTypes",
            query = "select dt from DepartmentType dt where dt.id=:dtId",
            hints = @QueryHint(name=QueryHints.HINT_LOADGRAPH, value = "departnemtsTypesWithDepartments")
)
public class DepartmentType {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @OneToOne(mappedBy="type")
    private Department department;

    //region getters

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //endregion
}




Вот этот код дает один запрос
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
public class Main {

   static EntityManagerFactory emf = Persistence.createEntityManagerFactory("default");

    public static void main(String[] args) {
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        EntityGraph gr = em.getEntityGraph("departnemtsTypesWithDepartments");
        em.createQuery("select dt from DepartmentType dt", DepartmentType.class)
                .setHint(QueryHints.HINT_LOADGRAPH, gr)
                .getResultList().forEach(dt->{
                        System.out.println(dt);
                        System.out.println(dt.getDepartment());
        });

        em.getTransaction().commit();

    }
}



А вот этот два
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
public class Main {

   static EntityManagerFactory emf = Persistence.createEntityManagerFactory("default");

    public static void main(String[] args) {
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        em.createNamedQuery("departmetTypes", DepartmentType.class)
                .setParameter("dtId", 337L)
                .getResultList().forEach(dt->{
                    System.out.println(dt);
                    System.out.println(dt.getDepartment());
        });

        em.getTransaction().commit();

    }
}



то есть хинт не работает.
И как тут быть?
...
Рейтинг: 0 / 0
11.09.2017, 13:27
    #39519138
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
А с HINT_FETCHGRAPH поведение такое же?
...
Рейтинг: 0 / 0
11.09.2017, 13:32
    #39519143
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Лысый дядькаА вот этот два

А почему не N+1? Один департамент в БД?
...
Рейтинг: 0 / 0
11.09.2017, 13:33
    #39519144
Лысый дядька
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Blazkowicz,

Ничего не меняется
...
Рейтинг: 0 / 0
11.09.2017, 13:35
    #39519147
Лысый дядька
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
BlazkowiczЛысый дядькаА вот этот два

А почему не N+1? Один департамент в БД?

Да, это тестовые данные. Я пробовал на других схемах, где больше данных, там получается N+1
...
Рейтинг: 0 / 0
11.09.2017, 14:28
    #39519204
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Лысый дядька,

Похоже на багу. Если только вы где-нибудь опечаток не наделали.
...
Рейтинг: 0 / 0
12.09.2017, 12:20
    #39519793
Лысый дядька
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
В общем и целом получается, что аннотации хибернейта не вполне выполняют контракт JPA
вот код из Хибернейта
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
@Target( { TYPE, PACKAGE })
@Retention(RUNTIME)
@Repeatable(NamedQueries.class)
public @interface NamedQuery {

	/**
	 * The name of this {@code NamedQuery}.
	 */
	String name();

	/**
	 * The query string for this {@code NamedQuery}.
	 */
	String query();

	/**
	 * The flush mode for this query.
	 */
	FlushModeType flushMode() default FlushModeType.PERSISTENCE_CONTEXT;

	/**
	 * Whether the query (results) is cacheable or not.  Default is {@code false}, that is not cacheable.
	 */
	boolean cacheable() default false;

	/**
	 * If the query results are cacheable, name the query cache region to use.
	 */
	String cacheRegion() default "";

	/**
	 * The number of rows fetched by the JDBC Driver per trip.
	 */
	int fetchSize() default -1;

	/**
	 * The query timeout (in seconds).  Default is no timeout.
	 */
	int timeout() default -1;

	/**
	 * A comment added to the generated SQL query.  Useful when engaging with DBA.
	 */
	String comment() default "";

	/**
	 * The cache mode used for this query.  This refers to entities/collections returned from the query.
	 */
	CacheModeType cacheMode() default CacheModeType.NORMAL;

	/**
	 * Whether the results should be read-only.  Default is {@code false}.
	 */
	boolean readOnly() default false;
}



Тут нет метода hints, в то время как в JPA он есть

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
@Target({TYPE})
@Retention(RUNTIME)
public @interface NamedQuery {

    /**
     * (Required) The name used to refer to the query with the {@link EntityManager}
     * methods that create query objects.
     */
    String name();

    /** (Required)
     * The query string in the Java Persistence query language.
     */
    String query();

    /**
     * (Optional) The lock mode type to use in query execution.  If a <code>lockMode</code>
     * other than <code>LockModeType.NONE</code> is specified, the query must be executed in
     * a transaction.
     * @since Java Persistence 2.0
     */
    LockModeType lockMode() default NONE;

    /** (Optional) Query properties and hints.  May include
     * vendor-specific query hints.
     */
    QueryHint[] hints() default {};
}
...
Рейтинг: 0 / 0
12.09.2017, 12:30
    #39519796
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Лысый дядькаВ общем и целом получается, что аннотации хибернейта не вполне выполняют контракт JPA
А они и не должны. Аннотации хибера к JPA отношения не имеют. Нужен контракт JPA - пользуешься аннотациями JPA. Я тоже было подумал, что где-то в коде Hibernate аннотации затесались. Но, вроде, нет. Весь маппинг на JPA ведь?
...
Рейтинг: 0 / 0
12.09.2017, 12:35
    #39519798
Лысый дядька
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
BlazkowiczЛысый дядькаВ общем и целом получается, что аннотации хибернейта не вполне выполняют контракт JPA
А они и не должны. Аннотации хибера к JPA отношения не имеют. Нужен контракт JPA - пользуешься аннотациями JPA. Я тоже было подумал, что где-то в коде Hibernate аннотации затесались. Но, вроде, нет. Весь маппинг на JPA ведь?

Маппинг на JPA, но сам факт, что аннотация из Хибернейта не знает о таком методе, наводит на мысль, что хибернейт его не поддерживает. Впрочем, техподдержка уже признала косяк.
...
Рейтинг: 0 / 0
12.09.2017, 12:38
    #39519799
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Лысый дядькапрочем, техподдержка уже признала косяк.
Я сходу тикета не нашел в трекере. Хотя не так уж и усердно искал. Номер не дали?
...
Рейтинг: 0 / 0
12.09.2017, 12:39
    #39519800
Лысый дядька
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
BlazkowiczЛысый дядькапрочем, техподдержка уже признала косяк.
Я сходу тикета не нашел в трекере. Хотя не так уж и усердно искал. Номер не дали?

https://forum.hibernate.org/viewtopic.php?f=1&t=1044821
...
Рейтинг: 0 / 0
12.09.2017, 12:49
    #39519807
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Лысый дядька https://forum.hibernate.org/viewtopic.php?f=1&t=1044821
Пфф. Так это они ничего не подтвердили. Перевожу:
"Может быть и бага. Заведите тикет с полноценным тестом, если хотите чтобы кто-то из разработчиков посмотрел".

Я бы в первую очередь подебажил бы код Hibernate. Это же opensource проект. И исходники там вменяемые. К тому же если вы в тикете ткнете в конкретный класс, который они провтыкали или даже патч приложене, то вероятность скорого исправление вырастет очень сильно.

Но меня очень удивит если это окажется багой. Потому как хинты, вроде, давно в JPA. И сценарий простейший.
...
Рейтинг: 0 / 0
12.09.2017, 12:56
    #39519816
Лысый дядька
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Blazkowicz,

Если представителю разработчика насрать, то мне тем более.
...
Рейтинг: 0 / 0
12.09.2017, 12:58
    #39519821
Лысый дядька
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Меня другое беспокоит. Неужели никто не создает именованных запросов на основе графов? Ну иначе бы проблема была известной.
А как тогда делают?
...
Рейтинг: 0 / 0
12.09.2017, 13:12
    #39519834
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Лысый дядькаЕсли представителю разработчика насрать, то мне тем более.
Я посмотрел исходники. Подтверждаю - бага есть.
org.hibernate.cfg.annotations.QueryBinder перекладывает данные запроса из JPA аннотации в NamedQueryDefinitionBuilder/NamedQueryDefinition.
И ни в одном из этих классов нет хинтов FETCH/LOAD.

В JIRA тоже постить не буду, потому что эти меньшинства нас забанили.
...
Рейтинг: 0 / 0
12.09.2017, 13:17
    #39519835
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
JPA @NamedQuery + @NamedEntityGraph
Лысый дядькаМеня другое беспокоит. Неужели никто не создает именованных запросов на основе графов? Ну иначе бы проблема была известной.
А как тогда делают?
Я сам в а.уе. EntityGraph это, ИМХО, одно из важнейших достижений ORM в нынешний период застоя.

Но багу не встречал, возможно, потому что сам делаю вот так:

Код: java
1.
2.
3.
4.
5.
6.
7.
@Repository
public interface BeanRepository extends JpaRepository<Bean, Long> {
    @Override
    @EntityGraph(value = "Bean.features", type = EntityGraph.EntityGraphType.LOAD)
    @Query("select distinct b from Bean b")
    List<CheckOutPolicy> findAll();
}
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / JPA @NamedQuery + @NamedEntityGraph / 16 сообщений из 16, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]