Получить ленивый PersistentCollection без вызова базы данных - PullRequest
1 голос
/ 14 сентября 2011

Есть ли способ получить свойство Collection сущности, когда вы уже знаете идентификатор родительской сущности и знаете, что сущность действительно существует в базе данных, , не вызывая запрос к базе данных ?

Самый простой способ получить такую ​​коллекцию - это, конечно, использовать EntityManager.find(), но он делает ненужный запрос к базе данных:

    MyEntity entity = em.find(MyEntity.class, id); // prints "select ... from MyEntity"
    Collection c = entity.getSomeChildren();

Я предполагал, что EntityManager.getReference() будетдобиваться цели, но, к сожалению, даже при getReference() база данных запрашивается при вызове entity.getSomeChildren(), несмотря на то, что это свойство FetchType.LAZY:

    MyEntity entity = em.getReference(MyEntity.class, id);
    Collection c = entity.getSomeChildren();       // prints "select ... from MyEntity"

К счастью, запрос "select ... from MyEntity_SomeChildren" не выдается, если толькоЯ на самом деле вызываю какой-то метод для c, и я понимаю, что этот последний эффект именно из-за аннотации FetchType.LAZY.Но я думаю, что даже первый запрос является излишним.

Вот код для MyEntity

@Entity
public class MyEntity {
    private String id;
    private Collection<SomeChildren> someChildren;

    @Id
    public String getId() {
        return id;
    }

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

    @OneToMany(fetch = FetchType.LAZY)
    public Collection<SomeChildren> getSomeChildren() {
        return someChildren;
    }

    public void setSomeChildren(Collection<SomeChildren> someCollection) {
        this.someChildren = someCollection;
    }
}

ОБНОВЛЕНИЕ: Зачем мне это нужно? Полный сценарийэто что-то вроде этого: у меня есть экземпляр MyEntity, который я получил из запроса с оператором new:

    @SuppressWarnings({"unchecked"})
    List<MyEntity> list = em.createQuery("select new MyEntity(...) from MyEntity e where ...").getResultList();
    MyEntity original = list.get(0);
    return  original;

Это прекрасно работает, но иногда (и только иногда )Мне нужно entity.getSomeChildren().Следовательно, я не хочу передавать его конструктору, поэтому я подумал об этом трюке:

    MyEntity original = list.get(0);
    MyEntity entity = em.getReference(MyEntity.class, original.getId());
    Collection c = entity.getSomeChildren(); // prints "select ... from MyEntity where id=?"
    original.setSomeChildren(c);
    return  original;

... в надежде, что он не выдаст запрос к базе данных, но, по-видимому, делает: (

1 Ответ

1 голос
/ 14 сентября 2011

Использование select new MyEntity(...) в вашем запросе означает, что вы используете MyEntity в качестве DTO: отдельный объект, содержащий некоторые поля фактического экземпляра MyEntity.

Если вы хотите, чтобы он ссылался на ленивую коллекцию детей, просто используйте select e from MyEntity e ...: вы получите прикрепленный экземпляр MyEntity с его ленивой (неинициализированной) коллекцией детей.И как только вы вызовете какой-либо метод дочерней коллекции, будет выполнен дополнительный запрос для загрузки этой коллекции.

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

Я бы не стал использовать класс MyEntity в качестве DTO, а вместо этого использовал бы выделенный класс, не содержащий список детей.Таким образом, для кода вызывающей стороны будет ясно, что для получения списка потомков потребуется выполнить дополнительный специальный HQL-запрос.

...