I'm using Spring Boot 2.x, Spring Data REST, Spring HATEOAS.
I'm exposing a Repository over REST:
#Transactional
#PreAuthorize("isAuthenticated()")
public interface DocumentRepository extends JpaRepository<Document, Long>, JpaSpecificationExecutor {
#Transactional(readOnly = true)
#Query("SELECT d FROM Document d LEFT JOIN FETCH Contact c ON d.contact.id=c.id WHERE d.type='SALES_ORDER' AND d.status='PENDING' AND d.store.id=:storeId AND (SELECT COUNT(row) FROM DocumentRow row JOIN ProductAvailability pa ON (pa.productCode=row.productCode AND pa.productType=row.productType) WHERE row.document.id=d.id AND row.product.id IS NOT NULL AND pa.qtyOnHand-pa.qtyAllocated < row.qty)=0")
Page<Document> findOrdersReadyToProcess(#Param("storeId") Long storeId, Pageable pageable);
Because I need some information of the Contact, I'm using a Spring Projection defined as:
#org.springframework.data.rest.core.config.Projection(name = "table", types = {Document.class})
public interface Projection {
Instant getCreatedDate();
Instant getDate();
boolean isElectronic();
BigDecimal getTotalAmount();
DocumentType getType();
String getCode();
String getFiscalReceiptNumber();
String getPurchaseRefCode();
DocumentStatus getStatus();
DocumentDeliveryStatus getDeliveryStatus();
boolean isAssemble();
ContactProjection getContact();
StoreProjection getStore();
}
and the ContactProjection is:
#Projection(types = {Contact.class})
public interface ContactProjection {
String getFullName();
}
Contact is defines as follows in Document entity:
#JsonDeserialize(using = ContactUriDeserializer.class)
#ManyToOne(fetch = FetchType.LAZY)
private Contact contact;
However, when I call the endpoint Hibernate do N subquery to fetch Contact information:
Hibernate: select document0_.`id` as id1_12_, document0_.`createdBy` as createdB2_12_, document0_.`createdDate` as createdD3_12_, document0_.`lastModifiedBy` as lastModi4_12_, document0_.`lastModifiedDate` as lastModi5_12_, document0_.`sid` as sid6_12_, document0_.`version` as version7_12_, document0_.`amount` as amount8_12_, document0_.`assemble` as assemble9_12_, document0_.`code` as code10_12_, document0_.`contact_id` as contact36_12_, document0_.`costAmount` as costAmo11_12_, document0_.`date` as date12_12_, document0_.`deliveryDate` as deliver13_12_, document0_.`deliveryStatus` as deliver14_12_, document0_.`destinationStore_id` as destina37_12_, document0_.`electronic` as electro15_12_, document0_.`embeddedContact` as embedde16_12_, document0_.`eyeExam_id` as eyeExam38_12_, document0_.`fiscalReceiptDate` as fiscalR17_12_, document0_.`fiscalReceiptNumber` as fiscalR18_12_, document0_.`fiscalReceiptPrintDate` as fiscalR19_12_, document0_.`fiscalReceiptSerialNumber` as fiscalR20_12_, document0_.`grossMargin` as grossMa21_12_, document0_.`grossProfit` as grossPr22_12_, document0_.`number` as number23_12_, document0_.`numberSeries` as numberS24_12_, document0_.`paymentTerm_id` as payment39_12_, document0_.`paymentType` as payment25_12_, document0_.`project_id` as project40_12_, document0_.`purchaseRefCode` as purchas26_12_, document0_.`rounding` as roundin27_12_, document0_.`sourceStore_id` as sourceS41_12_, document0_.`status` as status28_12_, document0_.`store_id` as store_i42_12_, document0_.`stsTaxDeductionDenial` as stsTaxD29_12_, document0_.`supplyType` as supplyT30_12_, document0_.`taxAmount` as taxAmou31_12_, document0_.`totalAmount` as totalAm32_12_, document0_.`type` as type33_12_, document0_.`workingDistance` as working34_12_, document0_.`year` as year35_12_ from `Document` document0_ left outer join `Contact` contact1_ on (document0_.`contact_id`=contact1_.`id`) where document0_.`type`='SALES_ORDER' and document0_.`status`='PENDING' and document0_.`store_id`=? and (select count(documentro2_.`id`) from `DocumentRow` documentro2_ inner join `ProductAvailability` productava3_ on (productava3_.`productCode`=documentro2_.`productCode` and productava3_.`productType`=documentro2_.`productType`) where documentro2_.`document_id`=document0_.`id` and (documentro2_.`product_id` is not null) and productava3_.`qtyOnHand`-productava3_.`qtyAllocated`<documentro2_.`qty`)=0 limit ?
Hibernate: select contact0_.`id` as id1_6_0_, contact0_.`createdBy` as createdB2_6_0_, contact0_.`createdDate` as createdD3_6_0_, contact0_.`lastModifiedBy` as lastModi4_6_0_, contact0_.`lastModifiedDate` as lastModi5_6_0_, contact0_.`sid` as sid6_6_0_, contact0_.`version` as version7_6_0_, contact0_.`billingAddress` as billingA8_6_0_, contact0_.`billingCity` as billingC9_6_0_, contact0_.`billingCountry` as billing10_6_0_, contact0_.`billingDistrict` as billing11_6_0_, contact0_.`billingZipCode` as billing12_6_0_, contact0_.`birthCity` as birthCi13_6_0_, contact0_.`birthDate` as birthDa14_6_0_, contact0_.`certifiedEmail` as certifi15_6_0_, contact0_.`companyName` as company16_6_0_, contact0_.`email` as email17_6_0_, contact0_.`fax` as fax18_6_0_, contact0_.`firstName` as firstNa19_6_0_, contact0_.`fullName` as fullNam20_6_0_, contact0_.`gender` as gender21_6_0_, contact0_.`iban` as iban22_6_0_, contact0_.`job` as job23_6_0_, contact0_.`landlinePhone` as landlin24_6_0_, contact0_.`lastName` as lastNam25_6_0_, contact0_.`mobilePhone` as mobileP26_6_0_, contact0_.`personType` as personT27_6_0_, contact0_.`preset` as preset28_6_0_, contact0_.`publicAdministration` as publicA29_6_0_, contact0_.`sdiAccountId` as sdiAcco30_6_0_, contact0_.`shippingAddress` as shippin31_6_0_, contact0_.`shippingCity` as shippin32_6_0_, contact0_.`shippingCountry` as shippin33_6_0_, contact0_.`shippingDistrict` as shippin34_6_0_, contact0_.`shippingZipCode` as shippin35_6_0_, contact0_.`store_id` as store_i45_6_0_, contact0_.`computerUser` as compute36_6_0_, contact0_.`drivingFrequency` as driving37_6_0_, contact0_.`electronicDeviceUser` as electro38_6_0_, contact0_.`jobCategory` as jobCate39_6_0_, contact0_.`sporty` as sporty40_6_0_, contact0_.`swift` as swift41_6_0_, contact0_.`taxCode` as taxCode42_6_0_, contact0_.`type` as type43_6_0_, contact0_.`vatNumber` as vatNumb44_6_0_ from `Contact` contact0_ where contact0_.`id`=?
Hibernate: select store0_.`id` as id1_40_0_, store0_.`createdBy` as createdB2_40_0_, store0_.`createdDate` as createdD3_40_0_, store0_.`lastModifiedBy` as lastModi4_40_0_, store0_.`lastModifiedDate` as lastModi5_40_0_, store0_.`sid` as sid6_40_0_, store0_.`version` as version7_40_0_, store0_.`address` as address8_40_0_, store0_.`certifiedEmail` as certifie9_40_0_, store0_.`city` as city10_40_0_, store0_.`code` as code11_40_0_, store0_.`country` as country12_40_0_, store0_.`district` as distric13_40_0_, store0_.`email` as email14_40_0_, store0_.`fax` as fax15_40_0_, store0_.`landlinePhone` as landlin16_40_0_, store0_.`mobilePhone` as mobileP17_40_0_, store0_.`name` as name18_40_0_, store0_.`zipCode` as zipCode19_40_0_ from `Store` store0_ where store0_.`id`=?
Hibernate: select contact0_.`id` as id1_6_0_, contact0_.`createdBy` as createdB2_6_0_, contact0_.`createdDate` as createdD3_6_0_, contact0_.`lastModifiedBy` as lastModi4_6_0_, contact0_.`lastModifiedDate` as lastModi5_6_0_, contact0_.`sid` as sid6_6_0_, contact0_.`version` as version7_6_0_, contact0_.`billingAddress` as billingA8_6_0_, contact0_.`billingCity` as billingC9_6_0_, contact0_.`billingCountry` as billing10_6_0_, contact0_.`billingDistrict` as billing11_6_0_, contact0_.`billingZipCode` as billing12_6_0_, contact0_.`birthCity` as birthCi13_6_0_, contact0_.`birthDate` as birthDa14_6_0_, contact0_.`certifiedEmail` as certifi15_6_0_, contact0_.`companyName` as company16_6_0_, contact0_.`email` as email17_6_0_, contact0_.`fax` as fax18_6_0_, contact0_.`firstName` as firstNa19_6_0_, contact0_.`fullName` as fullNam20_6_0_, contact0_.`gender` as gender21_6_0_, contact0_.`iban` as iban22_6_0_, contact0_.`job` as job23_6_0_, contact0_.`landlinePhone` as landlin24_6_0_, contact0_.`lastName` as lastNam25_6_0_, contact0_.`mobilePhone` as mobileP26_6_0_, contact0_.`personType` as personT27_6_0_, contact0_.`preset` as preset28_6_0_, contact0_.`publicAdministration` as publicA29_6_0_, contact0_.`sdiAccountId` as sdiAcco30_6_0_, contact0_.`shippingAddress` as shippin31_6_0_, contact0_.`shippingCity` as shippin32_6_0_, contact0_.`shippingCountry` as shippin33_6_0_, contact0_.`shippingDistrict` as shippin34_6_0_, contact0_.`shippingZipCode` as shippin35_6_0_, contact0_.`store_id` as store_i45_6_0_, contact0_.`computerUser` as compute36_6_0_, contact0_.`drivingFrequency` as driving37_6_0_, contact0_.`electronicDeviceUser` as electro38_6_0_, contact0_.`jobCategory` as jobCate39_6_0_, contact0_.`sporty` as sporty40_6_0_, contact0_.`swift` as swift41_6_0_, contact0_.`taxCode` as taxCode42_6_0_, contact0_.`type` as type43_6_0_, contact0_.`vatNumber` as vatNumb44_6_0_ from `Contact` contact0_ where contact0_.`id`=?
Hibernate: select contact0_.`id` as id1_6_0_, contact0_.`createdBy` as createdB2_6_0_, contact0_.`createdDate` as createdD3_6_0_, contact0_.`lastModifiedBy` as lastModi4_6_0_, contact0_.`lastModifiedDate` as lastModi5_6_0_, contact0_.`sid` as sid6_6_0_, contact0_.`version` as version7_6_0_, contact0_.`billingAddress` as billingA8_6_0_, contact0_.`billingCity` as billingC9_6_0_, contact0_.`billingCountry` as billing10_6_0_, contact0_.`billingDistrict` as billing11_6_0_, contact0_.`billingZipCode` as billing12_6_0_, contact0_.`birthCity` as birthCi13_6_0_, contact0_.`birthDate` as birthDa14_6_0_, contact0_.`certifiedEmail` as certifi15_6_0_, contact0_.`companyName` as company16_6_0_, contact0_.`email` as email17_6_0_, contact0_.`fax` as fax18_6_0_, contact0_.`firstName` as firstNa19_6_0_, contact0_.`fullName` as fullNam20_6_0_, contact0_.`gender` as gender21_6_0_, contact0_.`iban` as iban22_6_0_, contact0_.`job` as job23_6_0_, contact0_.`landlinePhone` as landlin24_6_0_, contact0_.`lastName` as lastNam25_6_0_, contact0_.`mobilePhone` as mobileP26_6_0_, contact0_.`personType` as personT27_6_0_, contact0_.`preset` as preset28_6_0_, contact0_.`publicAdministration` as publicA29_6_0_, contact0_.`sdiAccountId` as sdiAcco30_6_0_, contact0_.`shippingAddress` as shippin31_6_0_, contact0_.`shippingCity` as shippin32_6_0_, contact0_.`shippingCountry` as shippin33_6_0_, contact0_.`shippingDistrict` as shippin34_6_0_, contact0_.`shippingZipCode` as shippin35_6_0_, contact0_.`store_id` as store_i45_6_0_, contact0_.`computerUser` as compute36_6_0_, contact0_.`drivingFrequency` as driving37_6_0_, contact0_.`electronicDeviceUser` as electro38_6_0_, contact0_.`jobCategory` as jobCate39_6_0_, contact0_.`sporty` as sporty40_6_0_, contact0_.`swift` as swift41_6_0_, contact0_.`taxCode` as taxCode42_6_0_, contact0_.`type` as type43_6_0_, contact0_.`vatNumber` as vatNumb44_6_0_ from `Contact` contact0_ where contact0_.`id`=?
Hibernate: select contact0_.`id` as id1_6_0_, contact0_.`createdBy` as createdB2_6_0_, contact0_.`createdDate` as createdD3_6_0_, contact0_.`lastModifiedBy` as lastModi4_6_0_, contact0_.`lastModifiedDate` as lastModi5_6_0_, contact0_.`sid` as sid6_6_0_, contact0_.`version` as version7_6_0_, contact0_.`billingAddress` as billingA8_6_0_, contact0_.`billingCity` as billingC9_6_0_, contact0_.`billingCountry` as billing10_6_0_, contact0_.`billingDistrict` as billing11_6_0_, contact0_.`billingZipCode` as billing12_6_0_, contact0_.`birthCity` as birthCi13_6_0_, contact0_.`birthDate` as birthDa14_6_0_, contact0_.`certifiedEmail` as certifi15_6_0_, contact0_.`companyName` as company16_6_0_, contact0_.`email` as email17_6_0_, contact0_.`fax` as fax18_6_0_, contact0_.`firstName` as firstNa19_6_0_, contact0_.`fullName` as fullNam20_6_0_, contact0_.`gender` as gender21_6_0_, contact0_.`iban` as iban22_6_0_, contact0_.`job` as job23_6_0_, contact0_.`landlinePhone` as landlin24_6_0_, contact0_.`lastName` as lastNam25_6_0_, contact0_.`mobilePhone` as mobileP26_6_0_, contact0_.`personType` as personT27_6_0_, contact0_.`preset` as preset28_6_0_, contact0_.`publicAdministration` as publicA29_6_0_, contact0_.`sdiAccountId` as sdiAcco30_6_0_, contact0_.`shippingAddress` as shippin31_6_0_, contact0_.`shippingCity` as shippin32_6_0_, contact0_.`shippingCountry` as shippin33_6_0_, contact0_.`shippingDistrict` as shippin34_6_0_, contact0_.`shippingZipCode` as shippin35_6_0_, contact0_.`store_id` as store_i45_6_0_, contact0_.`computerUser` as compute36_6_0_, contact0_.`drivingFrequency` as driving37_6_0_, contact0_.`electronicDeviceUser` as electro38_6_0_, contact0_.`jobCategory` as jobCate39_6_0_, contact0_.`sporty` as sporty40_6_0_, contact0_.`swift` as swift41_6_0_, contact0_.`taxCode` as taxCode42_6_0_, contact0_.`type` as type43_6_0_, contact0_.`vatNumber` as vatNumb44_6_0_ from `Contact` contact0_ where contact0_.`id`=?
I want to avoid this N+1 SELECT problem! I tried several modification to the query, but every time I ended up to have these subqueries.
Am I doing something wrong? Why Hibernate doesn't fetch contact property and avoid subsequent subqueries?
Any hint would be appreciated.
Try to add the following annotation to your repository method:
#EntityGraph("contact")
I want to insert data into a table using the following code
public User registerUser(String usr, String pwd) {
u=em.find(User.class,usr);
if(u!=null)
{
return null;
}
String query1 = "insert into users values('" + usr + "','" + pwd +"')";
Query q = em.createQuery(query1);
u=em.find(User.class,usr);
return u;
}
here 'u' is the object of User class and em is EntityManager.
I get this following exception:
Servlet.service() for servlet action threw exception
org.hibernate.hql.ast.QuerySyntaxException: expecting OPEN, found 'values' near line 1, column 19 [insert into users values('pawan','am')]
Try
public User registerUser(String usr, String pwd) {
u=em.find(User.class,usr);
if(u!=null)
{
return null;
}
//Now saving...
em.getTransaction().begin();
em.persist(u); //em.merge(u); for updates
em.getTransaction().commit();
em.close();
return u;
}
If the PK is Identity, it will be set automatically in your persisted class, if you are using auto generation strategy (thanks to David Victor).
Edit to #aman_novice comment:
set it in your class
//Do this BEFORE getTransaction/persist/commit
//Set names are just a example, change it to your class setters
u.setUsr(usr);
u.setPwd(pwd);
//Now you can persist or merge it, as i said in the first example
em.getTransaction().begin();
(...)
About #David Victor, sorry I forgot about that.
You're not using SQL but JPAQL, there is no field-based insert. You persist object rather than inserting rows.
You should do something like this:
public User registerUser(String usr, String pwd) {
u=em.find(User.class,usr);
if(u!=null)
{
return u;
}
u = new User(usr, pwd);
em.persist(u);
return u;
}
This isn't really the way to go. You are trying to insert a row in a table but have no associated attached entity. If you're using the JPA entity manager - then create a new instance - set the properties & persist the entity.
E.g.
User u = new User();
u.setXXX(xx);
em.persist(u);
// em.flush() <<-- Not required, useful for seeing what is happening
// etc..
If you enable SQL loggging in Hibernate & flush the entity then you'll see what is sent to the database.
E.g. in persistence.xml:
<property name="hibernate.format_sql" value="true" />