Spring JPA EntityGraph извлекает все ленивые загруженные свойства

Я работал с Spring и Hibernate. Теперь взглянем на Spring Data JPA (2.0.3) с JPA 2.2

AgencyTicketType

@Entity
@Table(name = "agency_ticket_type", catalog = "test")
public class AgencyTicketType implements java.io.Serializable {
   private Long id;
   private String name;
   private Agency agency;
   private Set<AgencyTicketCategory> agencyTicketCategories = new HashSet<AgencyTicketCategory>(0);

   @Id
   @GeneratedValue(strategy = IDENTITY)
   @Column(name = "id", unique = true, nullable = false)
   public Long getId() {
     return this.id;
   }
   public void setId(Long id) {
    this.id = id;
   }
   @Column(name = "name", nullable = false, length = 100)
   public String getName() {
    return this.name;
   }
   public void setName(String name) {
    this.name = name;
   }
   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "agency_id", nullable = false)
   public Agency getAgency() {
     return this.agency;
   }
   public void setAgency(Agency agency) {
     this.agency = agency;
   }
   @OneToMany(fetch = FetchType.LAZY, mappedBy = "agencyTicketType")
   public Set<AgencyTicketCategory> getAgencyTicketCategories() {
      return this.agencyTicketCategories;
   }
   public void setAgencyTicketCategories(Set<AgencyTicketCategory> agencyTicketCategories) {
      this.agencyTicketCategories = agencyTicketCategories;
   }
}

AgencyTicketCategory

@Entity
@Table(name = "agency_ticket_category", catalog = "waytest")
public class AgencyTicketCategory implements java.io.Serializable {
    private Long id;
    private AgencyTicketType agencyTicketType;
    private String name;
    private BigDecimal price;
    private Set<TripTicket> tripTickets = new HashSet<TripTicket>(0);

    @Id
    @GeneratedValue(strategy = IDENTITY)

    @Column(name = "id", unique = true, nullable = false)
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "agency_ticket_type_id", nullable = false)
    public AgencyTicketType getAgencyTicketType() {
        return this.agencyTicketType;
    }
    public void setAgencyTicketType(AgencyTicketType agencyTicketType) {
        this.agencyTicketType = agencyTicketType;
    }
    @Column(name = "name", nullable = false, length = 100)
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Column(name = "price", nullable = false, precision = 8)
    public BigDecimal getPrice() {
        return this.price;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
    }
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "agencyTicketCategory")
    public Set<TripTicket> getTripTickets() {
        return this.tripTickets;
    }
    public void setTripTickets(Set<TripTicket> tripTickets) {
        this.tripTickets = tripTickets;
    }
}

вместилище

public interface TicketTypeRepository extends JpaRepository<AgencyTicketType, Long> {

  @EntityGraph(attributePaths={ "agencyTicketCategories" }, type=EntityGraphType.LOAD)
  @Query("select type from AgencyTicketType type where type.agency.code=?1")
  List<AgencyTicketType> findByAgency(String agencyCode);
}

обслуживание

@Service
public class TicketServiceImpl implements TicketService {       
    @Autowired private TicketTypeRepository ticketType;

    @Transactional(readOnly=true)
    @Override
    public List<AgencyTicketType> findByName(String code) {
        return ticketType.findByAgency(code);
    }    
}

Похоже, что при отладке в Service запрос охотно выбирает все лениво загруженные свойства - agency, agencyTicketCategories - и все их внутренние лениво-загруженные свойства, что приводит к ошибке сериализации JSON.

Нужно выбрать только эти

AgencyTicketTypes [
                   {
                     id, name,
                     agencyTicketCategories [
                                              {id,name,price},....
                                            ]
                   },.....    
                 ]

Могу ли я сделать это с @EntityGraph? Чего мне не хватает?

3 ответа

Указание отложенной загрузки - это только подсказка для провайдера JPA. В зависимости от используемого вами провайдера (Hibernate, EclipseLink и т. Д.), Он может быть полностью проигнорирован, и зависимости могут быть с нетерпением извлечены.

Что вам нужно сделать, это настроить, как ваши классы отображаются в JSON. Предполагая, что вы используете Джексон, вам может понадобиться использовать аннотации, такие как @JsonIgnore или же @JsonView, Вы также можете отобразить свой класс, который имеет только те поля, которые вам нужны.

Вы можете использовать аннотации Джексона @JsonBackReference/@JsonManagedReference, Они решают проблему бесконечной рекурсии с двунаправленными ссылками в объектной модели. Насколько я понимаю, это ваш случай.

См. http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion для получения дополнительной информации.

Стоит отметить, что отладка во время открытой транзакции (касающаяся коллекции) приведет к ее загрузке, даже если в реальном времени это не происходит. Другое дело, что, как упомянул @Apokralipsa, загрузка LAZY - всего лишь подсказка это можно полностью игнорировать и никогда не следует полагаться на какую-либо технику, которую вы используете

Другие вопросы по тегам