JPA ссылки: есть ли гарантии, связанные с содержанием поля? - PullRequest
0 голосов
/ 04 июня 2019

JPA EntityManager#getReference() возвращает что-то очень ленивое, обычно прокси.Он поступает в базу данных только при обращении к свойствам.Согласно документации:

Получить экземпляр, состояние которого может быть лениво извлечено

Что я хочу знать, так это то, имеет ли смысл изучать полятакой прокси.

У меня есть следующие два класса, которые формируют отношение один ко многим:

@Entity
@Table(name = "parent")
public class Parent {
    @Id
    @GeneratedValue
    public UUID id;
    public String name;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    public List<Child> children = new ArrayList<>();

    public void addChild(Child child) {
        children.add(child);
        child.parent = this;
    }

    public String getName() {
        return name;
    }

    public List<Child> getChildren() {
        return children;
    }
}

@Entity
@Table(name = "child")
public class Child {
    @Id
    @GeneratedValue
    public UUID id;
    public String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    public Parent parent;
}

Обратите внимание, что оба класса используют стратегию доступа к полю (так как @Idна поле, а не на получателе).

Я добавляю одну Parent с двумя дочерними элементами в базу данных во время настройки тестового набора через JDBC, чтобы избежать кэширования экземпляров Parent в EntityManager.Я не показываю этот код, так как он громоздкий и простой.Если это необходимо, я могу добавить его позже.

Затем я запускаю следующие тесты:

@Test
@Transactional
public void testWithFind() {
    Parent parent = entityManager.find(Parent.class, parentId);

    assertThat(parent.name, is("Joe"));
    assertThat(parent.children, hasSize(2));
}

@Test
@Transactional
public void testWithGetReference() {
    Parent parent = entityManager.getReference(Parent.class, parentId);

    assertNull(parent.name);
    assertThat(parent.children, hasSize(0));

    assertThat(parent.getName(), is("Joe"));
    assertThat(parent.getChildren(), hasSize(2));

    // ... but still ...
    assertNull(parent.name);
    assertThat(parent.children, hasSize(0));
}

Оба теста успешны.

Я вижу вконсоль, которая JPA фактически запрашивает базу данных.Для find() связанного теста это

Hibernate: select parent0_.id as id1_2_0_, parent0_.name as name2_2_0_ from parent parent0_ where parent0_.id=?
Hibernate: select children0_.parent_id as parent_i3_0_0_, children0_.id as id1_0_0_, children0_.id as id1_0_1_, children0_.name as name2_0_1_, children0_.parent_id as parent_i3_0_1_ from child children0_ where children0_.parent_id=?

Для getReference() это

Hibernate: select parent0_.id as id1_2_0_, parent0_.name as name2_2_0_ from parent parent0_ where parent0_.id=?
Hibernate: select children0_.parent_id as parent_i3_0_0_, children0_.id as id1_0_0_, children0_.id as id1_0_1_, children0_.name as name2_0_1_, children0_.parent_id as parent_i3_0_1_ from child children0_ where children0_.parent_id=?

Как видно, find() заполняет как String, так и коллекциюполе ок.Но для «сущности», возвращаемой getReference(), это не так: поля остаются в своем исходном состоянии даже после вызова получателей.

Я понимаю, что невозможно перехватить доступ к полю с помощью прокси(или, возможно, любой другой «юридический» механизм), поэтому прокси-сервер в основном работает на уровне получателей.Но сущности аннотированы для использования стратегии доступа к полям, поэтому пользователь явно ожидает, что поля будут использоваться для получения значений, а не для получения.Я не нашел никаких разъяснений в спецификации, и она ничего не говорит о семантике «только для получателя» для таких прокси (или я просто не нашел таких упоминаний).

Мои вопросы:

  1. Это несоответствие спецификации JPA, или я просто не понимаю ее правильно?

  2. Можно ли использовать поля для доступа к компонентам возвращаемой сущности

Я использую Hibernate 5.3.9 в качестве поставщика JPA.

1 Ответ

2 голосов
/ 04 июня 2019

Согласно спецификации JPA запрещено использовать публичный доступ к полям:

2.2 Постоянные поля и свойства

Постоянное состояние объекта доступно через постоянство среда выполнения провайдера [1] либо через средства доступа к свойствам стиля JavaBeans («Доступ к свойству») или через переменные экземпляра («доступ к полю»). Будь то постоянные свойства или постоянные поля или комбинация два используются для доступа провайдера к данному классу или объекту иерархия определяется, как описано в разделе 2.3 «Тип доступа».

Примечание по терминологии: постоянные поля и свойства объекта класс обычно упоминается в этом документе как «атрибуты» класса.

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

Требуется, чтобы класс сущности следует соглашениям подписи метода для JavaBeans свойства чтения / записи (как определено классом JavaBeans Introspector) для постоянных свойств при использовании доступа к свойствам.

В этом случае для каждого свойства постоянного свойства типа T сущности существует является методом получения, getProperty и методом установки setProperty. За логические свойства, isProperty может использоваться в качестве альтернативного имени для метод получения.

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