【问题标题】:JPA Lazy Fetch is not working when getting collectionJPA Lazy Fetch 在收集时不起作用
【发布时间】:2019-07-20 11:00:57
【问题描述】:

我正在获取一组对象,并尝试在 @ManyToOne 关系中使用 LAZY 加载来获取对象。但是,当我调用服务方法时,集合中的对象获取 NULL 值

List<Location> all = locationRepository.getLocations(ids);
Merchant merchant = all.get(0).getMerchant();
// merchant == null

LocationRepository.java

@Repository
public interface LocationRepository extends JpaRepository<Location, String> {

    @Query(value = "SELECT * FROM b_location WHERE id IN :ids", nativeQuery = true)
    List<Location> getLocations(@Param("ids") Set<String> ids);
    }

Location.java

@Entity
@Table(name = "b_location")
public class Location {

    @Id
    @Column(name = "id")
    private String id;

    @Column(name = "merchant_id", nullable = false)
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private Long merchantId;

    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "merchant_id", referencedColumnName = "id", insertable = false, updatable = false)
    private Merchant merchant;

    @Column(name = "is_active")
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private boolean isActive;

Merchant.java

@Entity
@Table(name = "b_merchant")
public class Merchant {

    @Id
    @Column(name = "id")
    private Long id;

    @Column(name = "merchant_name", nullable = false)
    private String merchantName;

    @Column(name ="is_premium", columnDefinition = "boolean default false", nullable = false)
    private boolean isPremium;

    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @OneToMany(mappedBy = "merchant", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private Set<Location> shops;

我想做什么:

1) 调用另一个查询,例如:

   @Query("SELECT l, l.merchant FROM Location l LEFT JOIN FETCH l.merchant WHERE l.id IN :ids")
    List<Location> getLocations(@Param("ids") List<String> ids);

@Query("SELECT l FROM Location l LEFT JOIN FETCH l.merchant WHERE l.id IN :ids")
        List<Location> getLocations(@Param("ids") List<String> ids);

@Query("from Location l left join fetch l.merchant where l.id IN (:ids)")
List<Location> getLocations(@Param("ids") List<String> ids);

2) 将 FetchType 更改为所有可能的类型 (fetch = FetchType.EAGER)

3) 使用

List<T> findAll(Iterable<ID> ids);
// and
List<Location> findByIdIn(List<String> ids);

附言

当我只得到一个对象时,它工作得非常好。例如:

Merchant merchant = locationRepository.findOne("11111").getMerchant();

更新

原来我对根本问题的理解是不正确的。在获取集合之前,我使用的是 locationRepository.save(location);手术。事实证明,JPA 有几个级别的缓存。我的问题是使用 EntityManager 解决缓存清理,例如:

entityManager.clear();

更多信息在这里: Invalidating JPA EntityManager session

但只要我的问题没有被正确提出,我建议 Maciej Kowalski 给出正确的答案。谢谢

【问题讨论】:

  • 您应该将查询更改为“SELECT l FROM Location l ...”。您的 getLocations 方法返回位置实体列表
  • 至于第二个选项,您必须在事务方法中进行。尝试在此方法中使用一些 Merchang getter -> locationRepository.findOne("11111").getMerchant().getId();
  • 我认为是因为你的自定义查询或方法,但你为什么不使用findAllByIdsdocs.spring.io/spring-data/jpa/docs/current/api/org/…
  • @alex valuiskyi 谢谢。感谢您的帮助(“SELECT l FROM Location l ...”和@Transactional)。不幸的是它仍然不起作用
  • @Deadpool 我曾尝试使用您的评论 (List findAll(Iterable ids);) 但它没有用。谢谢

标签: java hibernate spring-boot spring-data-jpa


【解决方案1】:

1)您在此处使用本机查询:

@Query(value = "SELECT * FROM b_location WHERE id IN :ids", nativeQuery = true)

在这种情况下,任何延迟加载都不起作用。结果对象与持久性上下文没有任何关联。

2) FetchType.LAZY 只是对持久性提供者的提示。它不必使关联变得懒惰,它可以决定急切地获取它。

3) 在您的情况下,您甚至不需要自定义查询。这应该有效:

List<Location> findByIdIn(List<String> ids);

【讨论】:

  • 在我的 JPA 版本中,我只有这个方法 (List findAll(Iterable ids);。我尝试使用它,但它没有用
  • 您可以在存储库接口中声明方法签名并使用它。框架创建方法实现
  • @alexvaluiskyi 谢谢,但这个选项也不起作用
  • @MaciejKowalski 你的意思是我应该删除这个 (FetchType.LAZY) 吗? ))
  • 不,它只是说明您可能无法在多对任意关联上实现延迟加载。
猜你喜欢
  • 2018-12-09
  • 2018-04-03
  • 2014-01-03
  • 1970-01-01
  • 1970-01-01
  • 2022-11-11
  • 2021-12-19
  • 1970-01-01
  • 2019-05-17
相关资源
最近更新 更多