Hibernate JPA2 - проблема выбора n + 1 затрагивает только одну сторону отношения OneToOne - PullRequest
1 голос
/ 16 апреля 2011

Я не получал ленивую загрузку ни для одного класса, пока не добавил инструментарий байт-кода через:

  <plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <executions>
      <execution>
        <phase>process-classes</phase>
        <goals>
          <goal>run</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <tasks>
        <taskdef name="instrument" classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
          <classpath>
            <path refid="maven.runtime.classpath" />
            <path refid="maven.plugin.classpath" />
          </classpath>
        </taskdef>
        <instrument verbose="false">
          <fileset dir="${project.build.outputDirectory}">
            <include name="**/db/**/*.class" />
          </fileset>
        </instrument>
      </tasks>
    </configuration>
  </plugin>

Вот два моих класса сущностей, сильно урезанных:

Эта таблица "из Ininvgrmtr" работает так, как я хочу (без n + 1 вопроса):

@Entity
@Table(name = "ININVGRMTR", catalog = "CO05IN", schema = "")
@XmlRootElement
public class Ininvgrmtr implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 8)
    @Column(name = "IGMGRUP", nullable = false, length = 8)
    private String igmgrup;

    //other attributes

    @JoinColumn(name = "IGMGRUP", referencedColumnName = "IGGRUP", nullable = false, insertable = false, updatable = false)
    @OneToOne(optional = false, fetch=FetchType.LAZY)
    private Ininvgrp ininvgrp;
}

Эта таблица "из Ininvgrp" не:

@Entity
@Table(name = "ININVGRP", catalog = "CO05IN", schema = "")
@XmlRootElement
public class Ininvgrp implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 8)
    @Column(name = "IGGRUP", nullable = false, length = 8)
    private String iggrup;

    //other attributes

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "ininvgrp", fetch=FetchType.LAZY)
    private Ininvgrmtr ininvgrmtr;

    //getters setters
} 

Для иллюстрации проблемы:

entityManagerFactory.createEntityManager().createQuery("from Ininvgrmtr").getResultList();

Печатает следующее в журнал (что хорошо):

INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_ from CO05IN.ININVGRMTR ininvgrmtr0_

В то время как,

entityManagerFactory.createEntityManager().createQuery("from Ininvgrp").getResultList();

Печать печатает следующее:

INFO: Hibernate: select ininvgrp0_.IGGRUP as IGGRUP97_, ininvgrp0_.Added as Added97_, ininvgrp0_.IGABCF as IGABCF97_, ininvgrp0_.IGADCN as IGADCN97_, ininvgrp0_.IGADDT as IGADDT97_, ininvgrp0_.IGADUS as IGADUS97_, ininvgrp0_.IGCAT as IGCAT97_, ininvgrp0_.IGDESC as IGDESC97_, ininvgrp0_.IGMDCN as IGMDCN97_, ininvgrp0_.IGMDDT as IGMDDT97_, ininvgrp0_.IGMDUS as IGMDUS97_, ininvgrp0_.IGRETH as IGRETH97_, ininvgrp0_.IGSTA as IGSTA97_, ininvgrp0_.IGTYPE as IGTYPE97_, ininvgrp0_.IGUBAS as IGUBAS97_, ininvgrp0_.IGUSEL as IGUSEL97_, ininvgrp0_.IGUWGT as IGUWGT97_, ininvgrp0_.Modified as Modified97_ from CO05IN.ININVGRP ininvgrp0_
INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_0_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_0_ from CO05IN.ININVGRMTR ininvgrmtr0_ where ininvgrmtr0_.IGMGRUP=?
INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_0_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_0_ from CO05IN.ININVGRMTR ininvgrmtr0_ where ininvgrmtr0_.IGMGRUP=?
INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_0_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_0_ from CO05IN.ININVGRMTR ininvgrmtr0_ where ininvgrmtr0_.IGMGRUP=?
INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_0_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_0_ from CO05IN.ININVGRMTR ininvgrmtr0_ where ininvgrmtr0_.IGMGRUP=?
INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_0_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_0_ from CO05IN.ININVGRMTR ininvgrmtr0_ where ininvgrmtr0_.IGMGRUP=?
INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_0_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_0_ from CO05IN.ININVGRMTR ininvgrmtr0_ where ininvgrmtr0_.IGMGRUP=?
INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_0_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_0_ from CO05IN.ININVGRMTR ininvgrmtr0_ where ininvgrmtr0_.IGMGRUP=?
INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_0_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_0_ from CO05IN.ININVGRMTR ininvgrmtr0_ where ininvgrmtr0_.IGMGRUP=?
INFO: Hibernate: select ininvgrmtr0_.IGMGRUP as IGMGRUP96_0_, ininvgrmtr0_.IGMTRACE as IGMTRACE96_0_ from CO05IN.ININVGRMTR ininvgrmtr0_ where ininvgrmtr0_.IGMGRUP=?
...

Что вызывает это?

1 Ответ

1 голос
/ 18 апреля 2011

Свойство Ininvgrmtr помечено как ненулевое и не является обязательным, поэтому hibernate знает, что должен существовать объект с данным идентификатором. Затем Hibernate может создать динамический прокси-сервер и установить его в качестве значения свойства. Этот прокси будет инициализирован только при доступе к его свойствам.

В другом направлении, начиная с Ininvgrp, свойство помечено как необязательное по умолчанию. Hibernate не может использовать динамический прокси в этом случае, так как он должен возвращать ноль, если нет соответствующей сущности.

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

Другим обходным решением было бы объявить свойство как отношение OneToMany и преобразовать его из пустого списка / одного элемента в null или его первый элемент в методах получения и установки следующим образом:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "ininvgrp", fetch=FetchType.LAZY)
private List<Ininvgrmtr> ininvgrmtr;

public void setIninvgrmtr(Ininvgrmtr ininvgrmtr) {
    if (this.ininvgrmtr == null || this.ininvgrmtr.isEmpty()) {
        this.ininvgrmtr = Collections.singletonList(ininvgrmtr);
    } else {
        this.ininvgrmtr.set(0, ininvgrmtr);
    }
}

public Ininvgrmtr getIninvgrmtr() {
    return ininvgrmtr == null || ininvgrmtr.isEmpty() ? null : ininvgrmtr.get(0);
}

Редактировать: Более подробное описание проблемы с некоторыми ссылками можно найти в этом сообщении в блоге .

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