Lasy Fetch с Spring Data JPA - PullRequest
       8

Lasy Fetch с Spring Data JPA

2 голосов
/ 26 мая 2020
• 1000 Я обнаружил, что Spring Data JPA игнорирует FetchType и с нетерпением извлекает все связанные таблицы (на основе связанных потоков и документов Spring Data JPA). Все методы Spring Data Repository, которые получают данные с помощью Distributor.class, выбирают Location двумя способами: от Distributor и Location. Используя @ NamedEntityGraph как таковой:
@Entity
@Table
@NamedEntityGraph(
        name = "distributor-entity-graph",
        attributeNodes = {
                @NamedAttributeNode("location"),
        }
)
public class Distributor {
//spring data jpa methods
  @EntityGraph(value = "distributor-entity-graph", type = EntityGraph.EntityGraphType.LOAD)
    Optional<Distributor> findById(Long id);

, я получаю одно левое внешнее соединение в Location, если использую такой график, и хотя это лучший тип активной нагрузки, он все еще жадная загрузка.

Все, что я нашел , кажется плохим обходным решением. Есть ли какой-нибудь более или менее изящный способ сделать это или, может быть, лучше (в первую очередь с точки зрения производительности) просто не создавать отношения и просто получать Location по запросу? Жадная загрузка - это неприятный запах, но когда я беру одного дистрибьютора, я хочу сделать именно это в большинстве случаев, но в некоторых случаях я этого не делаю, и особенно если я действительно findAll ().

1 Ответ

3 голосов
/ 27 мая 2020

Hibernate игнорирует LAZY на родительской стороне каждого двунаправленного взаимно-однозначного сопоставления, для которого установлено mappedBy (или использует JoinColumn и является необязательным), потому что ему нужно знать, когда инициализировать поле с нулевым значением или прокси.

Ваша проблема в том, что даже если вы используете MapsId для дочернего элемента (Location), родительский элемент по-прежнему использует mappedBy.

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

Родитель

@Entity
public class TestParent {

  @Id
  @GeneratedValue(strategy = IDENTITY)
  private Long id;

  @OneToOne(fetch = FetchType.LAZY, optional = false)
  @JoinColumn(name = "id")
  private TestChild child;
}
  • * Поле 1020 * не является обязательным , оно немного хакерское, и вы можете просто проигнорировать его и при необходимости получить дочерний элемент, используя репозиторий - вы знаете, что это id
  • Потому что это не стандартный родительский -to-child сопоставление, вы не можете указать какие-либо каскады в поле child (что будет отражать способ их сохранения, поэтому читайте до конца), иначе сохранение не удастся, потому что оно не сможет для присвоения идентификатора дочерней сущности.
  • * 103 0 * является обязательным , иначе он все равно будет загружен с нетерпением.

Ребенок

public class TestChild {

  @Id
  private Long id;

  @OneToOne(fetch = FetchType.LAZY)
  @MapsId
  @JoinColumn(name = "id")
  private TestParent parent;
}

Так вы определили своего ребенка, ничего important было изменено.

Сохранение

EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();

TestParent parent = new TestParent();
TestChild child = new TestChild();
parent.setChild(child);
child.setParent(parent);

em.persist(parent);
em.persist(child);

em.getTransaction().commit();
em.close();

Поскольку родительский элемент больше не каскадно передает дочерний объект, вам необходимо сохранить дочерний элемент отдельно.

Подробнее .

...