Java: многократный запуск запроса дочернего отображения в Spring Boot Application. - PullRequest
0 голосов
/ 29 марта 2020

У меня есть приложение весенней загрузки. Я создал спецификацию для поиска. Моя сущность Продукт содержит

@OneToOne
@JoinColumn(name="manufacturerID")
private Manufacturer manufacturer;

@OneToMany
@JoinColumn(name="key")
private List<Productattribute> productattributes;

@OneToMany
@JoinColumn(name="key")
private List<DsStatus> dsStatus;

@OneToMany
@JoinColumn(name="key")
private List<Media> medias;

@OneToMany
@JoinColumn(name="key")
private List<Distributormedia> distributormedias;

Мой запрос поиска при выполнении спецификации

select
    .....(fields)...........
from
    product product0_ 
inner join
    manufacturer manufactur1_ 
        on product0_.manufacturerID=manufactur1_.ManufacturerID 
inner join
    ds_status dsstatus2_ 
        on product0_.key=dsstatus2_.key 
left outer join
    media medias3_ 
        on product0_.key=medias3_.key 
left outer join
    distributormedia distributo4_ 
        on product0_.key=distributo4_.key 
where
    product0_.IsDeleted=0 
    and (
        product0_.serial in (
            select
                product5_.serial 
            from
                product product5_ 
            where
                product5_.IsDeleted=? 
                and (
                    product5_.Status in (
                        ? , ? , ? , ?
                    )
                ) 
            group by
                product5_.serial 
            having
                count(product5_.serial)>1
        )
    ) 
group by
    product0_.key

После выполнения этого запроса ... существует много подзапросов для извлечения детали из таблицы соединений. Если общее количество продукта равно 10, то выполняется 10 подзапросов для дочерней таблицы. Пример:

select
    manufactur0_.ManufacturerID as Manufact1_7_0_,
    manufactur0_.Address as Address2_7_0_
from
    manufacturer manufactur0_ 
where
    manufactur0_.ManufacturerID=?

На самом деле я не хочу подробностей из таблиц соединения. Я хочу только данные из родительской таблицы (продукта). Из-за этого требуется больше времени для возврата результата.

Добавление спецификации

    public Specification<Product> findByCriteria(List<Map<CriteriaSpecAttrKeys,Object>> searchCriteria) throws Exception {
               List<Predicate> predicates = new ArrayList<>();
               return (root, query, cb) -> {
                 try {
                   Join<Product, Manufacturer> manufacturer = root.join("manufacturer",JoinType.INNER);
                   Join<Product, DsStatus> dsStatus = root.join("dsStatus",JoinType.INNER);
                   Join<Product, Media> media = root.join("medias",JoinType.LEFT);
                   Join<Product, Distributormedia> distributormedia = root.join("distributormedias",JoinType.LEFT);
                   predicates.add(cb.equal(root.get("isDeleted"), false));
                   Subquery<Product> subquery = query.subquery(Product.class);
                    Root<Product> subroot = subquery.from(Product.class);
                    Predicate subpredicate1 = cb.equal(subroot.get("isDeleted"),false);
                    Predicate subpredicate2 = cb.in(subroot.get("status")).value("NEEDS_REVIEW").value("READY_FOR_PROD").value("IS_PROD_AVAIL").value("IN_PROD_NEEDS_REVIEW");

subquery.select(subroot.get("serial")).where(subpredicate1,subpredicate2).groupBy(subroot.get("serial")).having(cb.greaterThan(cb.count(subroot.get("serial")),1L));
                    predicates.add(cb.in(root.get("serial")).value(subquery));
                   query.groupBy(root.get("key"));
                   return cb.and(predicates.toArray(new Predicate[predicates.size()]));
                 }catch(Exception e) {
                   throw e;
                 }
               };
            }

Заранее спасибо

Обновление Я изменил OneToOne Отображение на

@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="manufacturerID")
private Manufacturer manufacturer;

Затем во время выполнения возникла исключительная ситуация.

ERROR 28185 --- [nio-8090-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.dmp.servicecontroller.response.Response["data"]->java.util.ArrayList[0]->com.product.entities.Product["manufacturer"]->com.manufacturer.entities.Manufacturer_$$_jvst266_1c["handler"])] with root cause

В исключительной ситуации рекомендуется to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS Поэтому я добавил @JsonIgnore, затем

@JsonIgnore
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="manufacturerID")
private Manufacturer manufacturer;

Это правильный метод?

Мой контроллер

    @RestController
    @RequestMapping(RestApiUrls.PRODUCT_BASE_URL)
    public class ProductController {
    @Autowired
    SearchSpecification searchSpecification;
    @Autowired
    ProductRepository productRepository;
        @PostMapping(RestApiUrls.SEARCH)
        public List<Product> productSearch(@Valid @RequestBody ProductSearchRequest productSearchRequest) {
            List<Product> productList = null;
            try {
                productList = productRepository.findAll(searchSpecification.findByCriteria(new ArrayList<>()));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return productList;
        }
    }

1 Ответ

0 голосов
/ 29 марта 2020

@ Отображение OneToOne по умолчанию является активным, что означает, что Hibernate выполнит дополнительный запрос для автоматического извлечения этих данных.

Просто измените тип извлечения, если вам не нужны эти данные:

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="manufacturerID")
private Manufacturer manufacturer;

Однако вы должны иметь в виду, что когда вы захотите вернуть из вашего контроллера сущность Product, Джексон попытается получить все ваши или все свойства или свойства с помощью getter (если они не помечены @JsonIgnore). Это означает, что Джексон вызовет ваш объект Product, например, метод getManufacturer (). Из-за отложенной загрузки это будет прокси, а не реальный объект. Hibernate попытается получить этот объект из базы данных. Если транзакции нет, вы получите исключение org.hibernate.LazyInitializationException.

Я предлагаю создать пользовательский ProductDto из сущности Product, который будет содержать только те данные, которые вы хотите вернуть, или использовать @JsonIgnore (как вы это сделали).

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