how to get alias name in Spring boot - spring

how to get alias name using spring-data-jpa in Spring boot?
I want alias name for stored procedure
StoredProcedureQuery storedProcedure = entitymanager.createStoredProcedureQuery(Proc);
if (params != null && params.length > 0) { // If no parameters supplied then no need to add it
int paramCount = 0;
for (String param : params) {
paramCount++;
storedProcedure.registerStoredProcedureParameter(paramCount, String.class, ParameterMode.IN);
storedProcedure.setParameter(paramCount, param);
// System.out.println("param" +param);
}
}
List<Object[]> storedProcedureResults = storedProcedure.getResultList();
this will return me only result but i also want column name which i have given in stored procedure

Related

Spring Boot Pagination is not working with custom DTO list

I am stuck with integrating pagination in Spring boot project.
Service Impl class
#Override
public Page<OnlineBuyProductReportItemDTO> generateOnlineBuyProductReport(String fromDate, String toDate, int pageNum, String sortField, String sortDir) {
Pageable pageable = PageRequest.of(pageNum - 1, 10,
sortDir.equals("asc") ? Sort.by(sortField).ascending()
: Sort.by(sortField).descending()
);
List<PurchaseOrder> purchaseOrderList = purchaseOrderRepository.searchPurchaseOrdersForOnlineBuyProductReport(
DateUtil.convertToDate(fromDate), DateUtil.convertToDate(toDate));
OnlineBuyProductReportItemDTO item = null;
List<OnlineBuyProductReportItemDTO> itemList = new ArrayList<OnlineBuyProductReportItemDTO>();
if(purchaseOrderList != null && purchaseOrderList.size() > 0) {
for (PurchaseOrder purchaseOrder : purchaseOrderList) {
item = new OnlineBuyProductReportItemDTO();
item.setOrderNumber(purchaseOrder.getOrderNumber());
item.setCreatedDate(DateUtil.convertDatetoStringSwissDate(purchaseOrder.getCreationTime()));
Address address = addressRepository.getAddressById(purchaseOrder.getBillingAddressId());
item.setCustomerName(address.getFullName());
item.setContactNumber(address.getTelephone());
List<OrderCart> orderCartList = orderCartRepository.getOrderCartByPurchaseOrderId(purchaseOrder.getId());
List<String> buyProductNameList = new ArrayList<String>();
if(orderCartList != null && orderCartList.size() > 0) {
for (OrderCart orderCart : orderCartList) {
buyProductNameList.add(orderCart.getProductName());
}
}
item.setProductName(buyProductNameList);
item.setPrice(purchaseOrder.getTotalPrice());
item.setStatus(purchaseOrder.getDeliveryStatus().getName());
itemList.add(item);
}
}
return new PageImpl<OnlineBuyProductReportItemDTO>(itemList, pageable,itemList.size());
}
Here I have fetch data from 3 database tables and after data processing I have added to these data to DTO List.
But, when after integrated with the front end, pagination options are displayed but did't work as expected.
All the pages containing same data set and also sorting options are not working as expected.
It seems this pageable part is not applying to the data processing.
Pageable pageable = PageRequest.of(pageNum - 1, 10,
sortDir.equals("asc") ? Sort.by(sortField).ascending()
: Sort.by(sortField).descending()
);
Is there any way to do this

Custom Result handling by calling store procedure in Spring Data JPA

I have requirement to call store procedures which takes input parameters. This store procedure returns custom result set, that result set i need to read and process further before return to UI. How we can achieve this?
EG:
#Query("CALL SP_EMPLOYEE_REPORT(:year)",nativeQuery = true)
List<EmpolypeeCustomReportBean> getEmployeeReport(#param("year") Integer year);
Given the following stored procedure.
CREATE PROCEDURE NAME_OF_THE_PROCEDURE(IN param VARCHAR(255), OUT retval INT)
You can call it from interface query:
#Procedure(value = "NAME_OF_THE_PROCEDURE")
int getFromStoredProcedure(String param);
Also by #Query annotation:
#Query(value = "CALL NAME_OF_THE_PROCEDURE(:input_value);", nativeQuery = true)
Integer findSomeThing(#Param("input_value") Integer name);
Or you can use named stored procedure query too.
#Entity
#NamedStoredProcedureQuery(name = "MyObj.getSomethingFromProc",
procedureName = "NAME_OF_THE_PROCEDURE", parameters = {
#StoredProcedureParameter(mode = ParameterMode.IN, name = "param", type = String.class),
#StoredProcedureParameter(mode = ParameterMode.OUT, name = "retval", type = Integer.class)})
public class MyObj{
// class definition
}
Then call it.
#Procedure(name = "MyObj.getSomethingFromProc")
Integer getSomethingFromStoredProc(#Param("param") String model);
Also you can use resultClasses and resultSetMapping properties in #NamedStoredProcedureQuery for complex return types.
Complex example provided by Eclipselink:
#NamedStoredProcedureQuery(
name="ReadUsingMultipleResultSetMappings",
procedureName="Read_Multiple_Result_Sets",
resultSetMappings={"EmployeeResultSetMapping", "AddressResultSetMapping", "ProjectResultSetMapping", "EmployeeConstructorResultSetMapping"}
)
#SqlResultSetMappings({
#SqlResultSetMapping(
name = "EmployeeResultSetMapping",
entities = {
#EntityResult(entityClass = Employee.class)
}
),
#SqlResultSetMapping(
name = "EmployeeConstructorResultSetMapping",
classes = {
#ConstructorResult(
targetClass = EmployeeDetails.class,
columns = {
#ColumnResult(name="EMP_ID", type=Integer.class),
#ColumnResult(name="F_NAME", type=String.class),
#ColumnResult(name="L_NAME", type=String.class),
#ColumnResult(name="R_COUNT", type=Integer.class)
}
)
}
)
})
public Employee(){
....
}

How to select data in spring boot using jpa based on where condition of jsonb column of postgres(without native query)?

I have Postgres database with jsonb field. I have used Predicate list for where condition with criteria builder in jpa. Now, I want to fetch JSON data stored in a database based on multiple where cause along with JSON. How it could be possible to do?
Database table
private List<Predicate> whereClause(CriteriaBuilder criteriaBuilder, Root<KafkaLog> kafkaLog,
KafkaLogSearchDto search) {
List<Predicate> predicates = new ArrayList<>();
if (search.getTopic() != null && !search.getTopic().isEmpty()) {
Expression<String> literal =
criteriaBuilder.literal("%" + search.getTopic().toUpperCase() + "%");
predicates.add(criteriaBuilder.like(criteriaBuilder.upper(kafkaLog.get("topic")), literal));
}
if (search.getOffset() != null) {
predicates.add(criteriaBuilder.equal(kafkaLog.get("offset"), search.getOffset()));
}
if (search.getResourceId() != null) {
predicates.add(criteriaBuilder.equal(kafkaLog.get("invoiceId"), search.getResourceId()));
}
if (search.getPartition() != null) {
predicates.add(criteriaBuilder.equal(kafkaLog.get("partition"), search.getPartition()));
}
if (search.getStatus() != null) {
predicates.add(criteriaBuilder.equal(kafkaLog.get("status"), search.getStatus()));
}
if (search.getCreatedAtFrom() != null && search.getCreatedAtTo() != null) {
predicates.add(criteriaBuilder.and(
criteriaBuilder.greaterThanOrEqualTo(kafkaLog.get("createdAt").as(Date.class),
search.getCreatedAtFrom()),
criteriaBuilder.lessThanOrEqualTo(kafkaLog.get("createdAt").as(Date.class),
search.getCreatedAtTo())));
}
if (search.getPayload() != null && !search.getPayload().isEmpty()) {
Expression<String> literal =
criteriaBuilder.literal("%" + search.getPayload().toUpperCase() + "%");
}
return predicates;
}
private CriteriaQuery<KafkaLog> getKafkaBySearchCriteria(KafkaLogSearchDto search, String orderBy,
int sortingDirection) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<KafkaLog> criteriaQuery = criteriaBuilder.createQuery(KafkaLog.class);
Root<KafkaLog> kafkaLog = criteriaQuery.from(KafkaLog.class);
List<Predicate> predicates = whereClause(criteriaBuilder, kafkaLog, search);
criteriaQuery.where(predicates.toArray(new Predicate[] {}));
if (orderBy == null || orderBy.isEmpty()) {
orderBy = "topic";
}
Expression<?> orderColumn = kafkaLog.get(orderBy);
if (orderColumn != null) {
if (sortingDirection == 0) {
criteriaQuery.orderBy(criteriaBuilder.asc(orderColumn));
} else if (sortingDirection == 1) {
criteriaQuery.orderBy(criteriaBuilder.desc(orderColumn));
}
}
return criteriaQuery;
}
apparently, custom data type support down to the JDBC/database level is not part of JPA itself. For just reading the JSON you might be able to do it with an entity mapping to String (if the JPA implementation does allow that).
However, you have some alternatives:
If you need to stick with JPA, you can implement a converter to handle the JSON for you (either generic as in this article or more specific - as you like): Using JPA with PostgreSQL JSON
If you can, ditch JPA and do it with JDBC/SQL directly, which gives you the full potential of PostgreSQL: how to store PostgreSQL jsonb using SpringBoot + JPA?
When reading the JSONB field, you can let the database do the conversion to String (as there is no direct JSON support in JDBC, yet) using explicit type conversion, e.g.:
SELECT payload::text FROM my_table WHERE ...
...or do some fancy filtering on the JSON field itself or return only a portion of the JSON data, aso.
This is example predicate to search jsonb with like clause :
predicate.getExpressions().add(cb.and(cb.like(cb.function("jsonb_extract_path_text", String.class, root.get("tags"), cb.literal(this.key)), "%"+ this.value + "%" )));

Ibatis TypeHandler and empty Varchar parameters in types in stored procedure

In a mybatis, spring application I have a TypeHandler which fills data for an ARRAY of STRUCTS required to call Oracle's stored procedure. A blob entry is properly filled and visible in the stored procedure; String entries are not, no string data is sent. No error or warning printed in logs. Data is not null and valid in application. The data simply disappears between application and oracle.
My handler's setParameter implementation looks like this:
public void setParameter(PreparedStatement ps, int i, List<MailAttachment> parameter,
JdbcType jdbcType) throws SQLException
{
List<MailAttachment> attachmentList = parameter;
OracleConnection oracleConnection = ps.getConnection().unwrap(OracleConnection.class);
StructDescriptor structDescriptor = StructDescriptor.createDescriptor(ATTACHMENT, oracleConnection);
Object[] structs = null;
structs = new Object[attachmentList == null ? 0 :attachmentList.size()];
if (attachmentList != null) {
//CharacterSet chs = CharacterSet.make(CharacterSet.UTF8_CHARSET);
for (int index = 0; index < attachmentList.size(); index++) {
MailAttachment mailAttachment = attachmentList.get(index);
BLOB blob = null;
if (mailAttachment.getData() != null){
blob = BLOB.createTemporary(oracleConnection,false,BLOB.DURATION_SESSION);
// filling blob works
}
CHAR attachName = new CHAR(mailAttachment.getFilename(), CharacterSet.make(CharacterSet.UTF8_CHARSET) );
CHAR contentType = new CHAR(mailAttachment.getContentType(), CharacterSet.make(CharacterSet.UTF8_CHARSET) );
STRUCT struct = new STRUCT(structDescriptor, oracleConnection,
new Object[] {blob, attachName, contentType, null}
);
structs[index] = struct;
}
}
ArrayDescriptor arrayDesc = ArrayDescriptor.createDescriptor(ATTACHMENT_LIST, oracleConnection);
ARRAY oracleArray = new ARRAY(arrayDesc, oracleConnection, structs);
ps.setObject(i, oracleArray);
}
This issue is connected with Oracle JDBC driver and it's support for internationalization.
Remember to include orai18n.jar in classpath/pom file in correct version for your ojdbc jar file.
If orai18n.jar is missing:
setParameters: varchar2 parameters in Oracle type will be set to null
getResult/getNonNullParameter: varchar2 parameters will be loaded to java class as "???" string.

How to Pass Java List of Objects to Oracle Stored Procedure Using MyBatis?

I have been googling this for a while and cannot seem to find any real answers.
I have an Oracle stored procedure that has a number of in parameters that have a type that is table of the table rowtype. So for example:
Declared in the pacakge:
TYPE param1_type_t IS TABLE OF table1%ROWTYPE;
TYPE param2_type_t IS TABLE OF table2%ROWTYPE;
TYPE param3_type_t IS TABLE OF table3%ROWTYPE;
Oracle Procedure:
PROCEDURE my_proc
(
parameter1 IN param1_type_t,
parameter2 IN param2_type_t,
parameter3 IN param3_type_t
)
On the java side, I have 3 corresponding Lists of objects representing each of the parameters that are populated in Java. Is it possible to call the Oracle procedure using MyBatis in this scenario?
<update id="callOracleSP" statementType="CALLABLE">
{CALL my_proc( #{param1, mode=IN},
#{param2, mode=IN},
#{param3, mode=IN}
)
}
</update>
The objects themselves are simple VOs with String and Integer properties and their respective getters and setters.
I am not really sure how to proceed. Do I need to somehow map the Java object lists to the Oracle types?
I can't tell if you do already or not, but you'll need Oracle objects defined.
CREATE OR REPLACE TYPE SCHEMA."YOUR_OBJECT" AS OBJECT
(
field_one varchar2(50),
field_two varchar2(100)
);
/
CREATE OR REPLACE TYPE SCHEMA."YOUR_OBJECT_ARRAY" AS TABLE OF YOUR_OBJECT;
/
Then you can write type handlers to map the Java objects to the Oracle objects.
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
....
public class YourTypeHandler implements TypeHandler
{
....
public void setParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException
{
List<YourObject> objects = (List<YourObject>) parameter;
StructDescriptor structDescriptor = StructDescriptor.createDescriptor("YOUR_OBJECT", ps.getConnection());
STRUCT[] structs = new STRUCT[objects.size()];
for (int index = 0; index < objects.size(); index++)
{
YourObject pack = packs.get(index);
Object[] params = new Object[2];
params[0] = pack.getFieldOne();
params[1] = pack.getFieldTwo();
STRUCT struct = new STRUCT(structDescriptor, ps.getConnection(), params);
structs[index] = struct;
}
ArrayDescriptor desc = ArrayDescriptor.createDescriptor("YOUR_OBJECT_ARRAY", ps.getConnection());
ARRAY oracleArray = new ARRAY(desc, ps.getConnection(), structs);
ps.setArray(i, oracleArray);
}
}
Then invoke the procedure,
call your_proc
(
#{yourObjects, javaType=Object, jdbcType=ARRAY, jdbcTypeName=YOUR_OBJECT_ARRAY, mode=IN, typeHandler=YourObjectArrayTypeHandler}
)
Andy Pryor's answer is very good I tested it and it really works. But it has an error at typeHandler:
call your_proc
(
#{yourObjects, javaType=Object, jdbcType=ARRAY, jdbcTypeName=YOUR_OBJECT_ARRAY, mode=IN, typeHandler=YourObjectArrayTypeHandler}
)
should be:
call your_proc
(
#{yourObjects, javaType=Object, jdbcType=ARRAY, jdbcTypeName=YOUR_OBJECT_ARRAY, mode=IN, typeHandler=YourTypeHandler}
)
The TypeHandler has an error as well: (there is no "packs" and there is some difference in the method parameters in my version)
#Override
public void setParameter(PreparedStatement ps, int i, Object parameter, String arg3) throws SQLException {
List<YourObject> objects = (List<YourObject>) parameter;
StructDescriptor structDescriptor = StructDescriptor.createDescriptor("YOUR_OBJECT", ps.getConnection());
STRUCT[] structs = new STRUCT[objects.size()];
for (int index = 0; index < objects.size(); index++)
{
YourObject pack = objects.get(index);
Object[] params = new Object[2];
params[0] = pack.getFieldOne();
params[1] = pack.getFieldTwo();
STRUCT struct = new STRUCT(structDescriptor, ps.getConnection(), params);
structs[index] = struct;
}
ArrayDescriptor desc = ArrayDescriptor.createDescriptor("YOUR_OBJECT_ARRAY", ps.getConnection());
ARRAY oracleArray = new ARRAY(desc, ps.getConnection(), structs);
ps.setArray(i, oracleArray);
}
And here is an example for xml mapping:
<parameterMap id="updateHierPersonAssignMap" class="java.util.Map" >
<parameter property="p_array" jdbcType="ARRAY" javaType="Object" mode="IN" typeHandler="com.aamtech.ria.model.domain.typehandler.YourTypeHandler"/>
</parameterMap>
<procedure id="updateHierPersonAssign" parameterMap="updateHierPersonAssignMap" >
<![CDATA[
{ call ria_am_util_pkg.j_update_hier_person_assign( ? ) }
]]>
</procedure>
And here is how you can call it from the DAO:
public void update(List array) {
Map<String, Object> queryParams = new HashMap<String, Object>();
queryParams.put("p_array", array);
try {
client.update("HashMapResult.updateHierPersonAssign", queryParams);
} catch (SQLException e) {
}
}
And my procedure looks like this (it just inserts a row into a test table):
Procedure j_update_hier_person_assign (p_array IN YOUR_OBJECT_ARRAY) is
begin
FOR i IN 1..p_array.count LOOP
--dbms_output.put_line();
insert into test (a) values (p_array(i).field_one);
END LOOP;
end;

Resources