I have a spring boot application. I have created a Specification for a search. My Entity Product contains
@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;
My Search query while running the Specification
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
After running the this query..there a lot of sub query for fetching the details from the Join table. If the total number of product is 10 then 10 subquery for the child table is running. Example:
select
manufactur0_.ManufacturerID as Manufact1_7_0_,
manufactur0_.Address as Address2_7_0_
from
manufacturer manufactur0_
where
manufactur0_.ManufacturerID=?
Actually I don't want details from the join tables. I only want the data from parent table (product). Because of this it takes more time to return the result.
Adding the Specification
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;
}
};
}
Thanks in Advance
Updating I changed the OneToOne Mapping to
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="manufacturerID")
private Manufacturer manufacturer;
Then there is an exception occured on run time.
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
In the exception, it is recommended for to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS
So I added @JsonIgnore, then
@JsonIgnore
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="manufacturerID")
private Manufacturer manufacturer;
Is it a correct method?
My Controller
@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;
}
}