I have a query and it works well on the database. However, when I tried to take them as a Java object by using RowMapper, I get an invalid column name error. I checked everything, but I don't understand the reason why this error happening.
My query:
SELECT TEMP.SUMALLTXN, SUM(TEMP.SUMCARD), SUM(TEMP.SUMERRORTXN), SUM(TEMP.SUMERRORTXNCARD)
FROM
(SELECT
SUM(COUNT(*)) OVER() AS SUMALLTXN,
COUNT(mdmtxn.BIN) OVER (PARTITION BY mdmtxn.BIN) AS SUMCARD,
SUM(case when mdmtxn.MDSTATUS NOT IN ('1','9', '60') then 1 else 0 end) AS SUMERRORTXN,
SUM(case when mdmtxn.MDSTATUS NOT IN ('1','9', '60') then 1 else 0 end) OVER (PARTITION BY mdmtxn.BIN) AS SUMERRORTXNCARD
FROM MDM59.MDMTRANSACTION2 mdmtxn WHERE
mdmtxn.CREATEDDATE < TO_CHAR(SYSDATE - INTERVAL ':initialMinuteParameterValue' MINUTE ,'YYYYMMDD HH24:MI:SS') AND
mdmtxn.CREATEDDATE > TO_CHAR(SYSDATE - INTERVAL ':intervalMinuteParameterValue' MINUTE ,'YYYYMMDD HH24:MI:SS')
GROUP BY mdmtxn.MDSTATUS, mdmtxn.BIN
) TEMP
GROUP BY TEMP.SUMALLTXN
My RowMapper:
#Component
public class TotalTransactionsReportRw implements RowMapper<TotalTransactionsReportDto> {
#Override
public TotalTransactionsReportDto mapRow(ResultSet rs, int rowNum) throws SQLException {
return TotalTransactionsReportDto.builder()
.totalNumbersOfTransactions(rs.getString("SUMALLTXN"))
.totalNumbersOfCard(rs.getString("SUMCARD"))
.totalNumbersOfErrorTransactions(rs.getString("SUMERRORTXN"))
.totalNumbersOfErrorCard(rs.getString("SUMERRORTXNCARD"))
.build();
}
private static class TotalTransactionsDetailRwHolder {
private static final TotalTransactionsReportRw INSTANCE = new TotalTransactionsReportRw();
}
public static TotalTransactionsReportRw getInstance() {
return TotalTransactionsReportRw.TotalTransactionsDetailRwHolder.INSTANCE;
}
}
My Dto:
#Value
#Builder
#Data
public class TotalTransactionsReportDto {
private String totalNumbersOfTransactions;
private String totalNumbersOfCard;
private String totalNumbersOfErrorTransactions;
private String totalNumbersOfErrorCard;
}
And in my tasklet class I created a list to get all data from rowmapper:
#Slf4j
#Component
#RequiredArgsConstructor
public class NotificationTasklet implements Tasklet {
private final PofPostOfficeServiceClient pofPostOfficeServiceClient;
private final SequenceSysGuid sequenceSysGuid;
private final BatchProps batchProps;
private JdbcTemplate jdbcTemplate;
private String notificationMailSql;
private String totalTransactionsSql;
private String endOfHtmlString = "</table></body></html>";
private String endOfTableString = "</table>";
private String jobName = "vpos-notification";
private String tdClose = "</td>";`
#Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
List<VposNotificationBatchDto> notificationList = getNotificationList();
List<TotalTransactionsReportDto> totalTransactionsList = getTotalTransactionsList();
AlertMailDto alertMailDto = createAlertMailDto(notificationList,totalTransactionsList);
if (!(notificationList.isEmpty())) {
sendMail(alertMailDto);
}
return RepeatStatus.FINISHED;
}
List<TotalTransactionsReportDto> getTotalTransactionsList() {
return jdbcTemplate.query(
totalTransactionsSql,
new TotalTransactionsReportRw());
}
#Autowired
public void setTotalTransactionsSql(#Value("classpath:sql/vposnotification/select_total_transactions_data.sql")
Resource res) {
int intervalnext = batchProps.getJobProps()
.get(jobName).getAlertProps().getIntervalMinuteParameterValue();
String intervalMinutes = String.valueOf(intervalnext);
int initialMinuteParameterValue = batchProps.getJobProps()
.get(jobName).getAlertProps().getInitialMinuteParameterValue();
String initialMinutes = String.valueOf(initialMinuteParameterValue);
this.totalTransactionsSql = SqlUtils.readSql(res);
this.totalTransactionsSql = this.totalTransactionsSql.replace(":initialMinuteParameterValue", initialMinutes);
this.totalTransactionsSql = this.totalTransactionsSql.replace(":intervalMinuteParameterValue", intervalMinutes);
}
#Autowired
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
The problem is that your query doesn't actually have columns SUMCARD, SUMERRORTXN and SUMERRORTXNCARD. Although there are DBMSes that alias SUM columns with the name of the column that is summed, Oracle is not one of them. IIRC, Oracle aliases it as, for example, "SUM(SUMCARD)" or maybe "SUM(TEMP.SUMCARD)". However, that is an implementation detail you should not rely on in my opinion.
To get the name you want to use, you need to alias your SUM columns explicitly, e.g. SUM(TEMP.SUMCARD) AS SUMCARD.
Related
My PoIs class:
public class PoIs {
private Integer location_id;
private String location_name;
private String location_address;
public PoIs() {}
public PoIs(Integer location_id, String location_name, String location_address) {
this();
this.location_id = location_id;
this.category_id = category_id;
this.location_name = location_name;
this.location_address = location_address;
}
public Integer get_location_id() {
return location_id;
}
public void set_location_id(Integer location_id) {
this.location_id = location_id;
}
public String get_location_name() {
return location_name;
}
public void set_location_name(String location_name) {
this.location_name = location_name;
}
public String get_location_address() {
return location_address;
}
public void set_location_address(String location_address) {
this.location_address = location_address;
}
I populate PoIs with informatision from a sqlite database:
final PoIs p = new PoIs(Integer.parseInt(row.get(0).toString()), row.get(1).toString(), row.get(2).toString());
and at a moment intend to save them on a firabase database:
FIREBASE_REFERENCE.child("PoI_"+ p.get_location_id()).setValue(p)
.addOnCompleteListener(t -> {
final boolean isSuccessful = t.isSuccessful();
final String msg = !isSuccessful
? getResources().getString(R.string.fb_error)
: getResources().getString(R.string.fb_success);
});
All work perfect except that my firebase fields start with an underscore. Instead location_id, location_name, location_address I have _location_id, _location_name, _location_address. I can't understand why this happening. Any ideea how to resolve this issue?
Firebase uses JavaBean naming conventions when mapping from properties in your code to properties in the database. In that convention a method like get_location_name is the getter for a property called _location_name.
If you want the property in the database to be location_name, that'd be a getter getLocation_name. Alternatively, you can use a #PropertyName("location_name")) annotation on all accessors (so the getter/setter function and/or the public field) to indicate the explicit property name you want in the database.
Still playing around and trying to understand the "how" of Spring's Webflux and Reactor.
The following successfully adds a new DemoPOJO to the repo when the annotated controller is used (i.e., POST issued at //localhost:8080/v1/DemoPOJO).
However, when issuing the same POST using the router/handler implementation (i.e., //localhost:8080/v2/DemoPOJO), request.bodyToMono(DemoPOJO.class) does not appear to retrieve the DemoPOJO instance from the ServerRequest (i.e., DemoPOJO.printme() is not being invoked).
I'm "working on this", but thought I'd see if anyone can help me "get there faster". For-what-it's-worth, the router/handler implementations (i.e., GET) that don't require getting a DemoPOJO out of ServerRequest are working.
RESTful endpoints using annotation...
#RestController
public class DemoPOJOController {
private Logger logger = LoggerFactory.getLogger(DemoPOJOHandler.class);
#Autowired
DemoPOJOService service;
#RequestMapping(method = POST, value = "/v1/DemoPOJO")
public Mono<Boolean> addDemoPOJO(#RequestBody DemoPOJO demoPOJO) {
logger.debug("DemoPOJOController.addDemoPOJO( {} )", demoPOJO.getId());
return service.add(demoPOJO);
}
}
"Router" part of the corresponding router/handler implementation...
#Configuration
public class DemoPOJORouter {
private Logger logger = LoggerFactory.getLogger(DemoPOJOHandler.class);
#Bean
public RouterFunction<ServerResponse> route(DemoPOJOHandler requestHandler) {
logger.debug("DemoPOJORouter.route( DemoPOJOHandler )");
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
RouterFunctions.route(RequestPredicates.POST("/DemoPOJO"), requestHandler::add)));
}
}
"Handler" part of the router/handler implementation...
#Component
public class DemoPOJOHandler {
public static final String PATH_VAR_ID = "id";
private Logger logger = LoggerFactory.getLogger(DemoPOJOHandler.class);
#Autowired
private DemoPOJOService service;
public Mono<ServerResponse> add(ServerRequest request) {
logger.debug("DemoPOJOHandler.add( ServerRequest )");
request.bodyToMono(DemoPOJO.class).doOnSuccess(DemoPOJO::printMe);
return ServerResponse.ok().build();
}
}
DemoPOJORepo implementation (hoping to simplify my learning experience by avoiding a "real" repository)...
#Component
public class DemoPOJORepo {
private static final int NUM_OBJS = 15;
private Logger logger = LoggerFactory.getLogger(DemoPOJORepo.class);
private static DemoPOJORepo demoRepo = null;
private Map<Integer, DemoPOJO> demoPOJOMap;
private DemoPOJORepo() {
logger.debug("DemoPOJORepo.DemoPOJORepo()");
initMap();
}
public boolean add(DemoPOJO demoPOJO) {
logger.debug("DemoPOJORepo.add( DemoPOJO )");
boolean pojoAdded = false;
if (!demoPOJOMap.containsKey(demoPOJO.getId())) {
logger.debug("DemoPOJORepo.add( DemoPOJO ) -> adding for id {}", demoPOJO.getId());
demoPOJOMap.put(demoPOJO.getId(), demoPOJO);
pojoAdded = true;
}
return pojoAdded;
}
private void initMap() {
logger.debug("DemoPOJORepo.initMap()");
demoPOJOMap = new TreeMap<Integer, DemoPOJO>();
for (int ndx = 1; ndx < (NUM_OBJS + 1); ndx++) {
demoPOJOMap.put(ndx, new DemoPOJO(ndx, "foo_" + ndx, ndx + 100));
}
}
}
The objects being manipulated...
public class DemoPOJO {
private Logger logger = LoggerFactory.getLogger(DemoPOJOHandler.class);
public static final String DEF_NAME = "DEFAULT NAME";
public static final int DEF_VALUE = 99;
private int id;
private String name;
private int value;
public DemoPOJO(int id) {
this(id, DEF_NAME, DEF_VALUE);
}
public DemoPOJO(#JsonProperty("id") int id, #JsonProperty("name") String name, #JsonProperty("value") int value) {
logger.debug("DemoPOJO.DemoPOJO( {}, {}, {} )", id, name, value);
this.id = id;
this.name = name;
this.value = value;
}
// getters and setters go here
public void printMe() {
logger.debug("DemoPOJO.printMe()");
System.out.printf("id->%d, name->%s, value->%d%n", id, name, value);
}
}
i am guesstimating here since i am writing from mobile. But i think this is your problem.
request.bodyToMono(DemoPOJO.class).doOnSuccess(DemoPOJO::printMe);
return ServerResponse.ok().build();
You are thinking imperative, that first row will be executed then the second which is not the case in webflux. You have to think events-callbacks.
return request.bodyToMono(DemoPOJO.class)
.doOnSuccess(DemoPOJO::printMe)
.thenReturn(ServerResponse.ok().build());
I think this is it but i could be wrong.
I tried mocking the JdbcTemplate jdbcTemplate ,but that didn't cover whatever is inside
new Employee(.......);
Please let me know is there any way to cover those lines inside new Employee(...)?
public List<Employee> findByCustIdAndType(long Id, String type)
{
return jdbcTemplate.query(SQL.getEmployee(Id, type),
(rs, rowNum) -> new Employee(rs.getLong("CUSTOMER_ID"),
rs.getLong("ANCHOR_CUSTOMER_ID") ,
rs.getString("SEGMENT"),
rs.getDate("END_TS")));
}
Try using Mockito to capture the lambda, which is a RowMapper<Employee>. Then invoke it with a mock ResultSet set up to return the expected values so the returned Employee can be asserted. Here's an example:
#RunWith(MockitoJUnitRunner.class)
public class EmployeeDAOTest {
private static final long CUSTOMER_ID = 1;
private static final long ANCHOR_CUSTOMER_ID = 2;
private static final String SEGMENT = "A";
private static final Date END_TS = Date.valueOf(LocalDate.now());
#InjectMocks
private EmployeeDAO dao;
#Mock
private JdbcTemplate jdbcTemplate;
#Mock
private ResultSet resultSet;
#Captor
private ArgumentCaptor<RowMapper<Employee>> rowMapperCaptor;
#Before
public void prepareTest() throws SQLException {
when(resultSet.getLong("CUSTOMER_ID")).thenReturn(CUSTOMER_ID);
when(resultSet.getLong("ANCHOR_CUSTOMER_ID")).thenReturn(ANCHOR_CUSTOMER_ID);
when(resultSet.getString("SEGMENT")).thenReturn(SEGMENT);
when(resultSet.getDate("END_TS")).thenReturn(END_TS);
}
#Test
public void test() throws SQLException {
dao.findByCustIdAndType(0, null);
verify(jdbcTemplate).query(anyString(), rowMapperCaptor.capture());
RowMapper<Employee> rowMapper = rowMapperCaptor.getValue();
Employee employee = rowMapper.mapRow(resultSet, 1);
assertEquals(CUSTOMER_ID, employee.getCustomerId());
assertEquals(ANCHOR_CUSTOMER_ID, employee.getAnchorCustomerId());
assertEquals(SEGMENT, employee.getSegment());
assertEquals(END_TS, employee.getEndTs());
}
}
I need to make a method getUserById witch will return 1 user by its id. I think that I need to use HashMap so here is my method :
public class UserDao {
private static final String SELECT_USERS = "select * from users_Alana";
public static List<User> getUsers(JdbcTemplate jdbcTemplate){
return jdbcTemplate.query(SELECT_USERS,new UserMapper());
}
private static class UserMapper implements RowMapper<User> {
#Nullable
public User mapRow(ResultSet resultSet, int i) throws SQLException {
User user = new User();
user.setId(resultSet.getInt("id"));
user.setName(resultSet.getString("name"));
user.setGender(resultSet.getString("gender"));
user.setAge(resultSet.getInt("age"));
return user;
}
}
public static void getUserById(int number) throws SQLException {
HashMap<Integer,User> getUser = new HashMap<Integer, User>();
if (getUser.containsKey(number)) {
System.out.println(getUser);
}
}
}
I call this method in a main class by UserDao.getUserById(2); Also I have a class User (with int id, age; String name, gender;) Constructor, getters and setters in it.
The result is nothing. How to solve it?
To get the user by id, I don't think you need a HashMap you can just use :
public static void getUserById(int id) throws SQLException {
UserDao dao = new UserDao();
List<User> users = dao.getUsers(jdbcTemplate);//This return a List or users
User user = user.stream()
.filter(u -> u.getId() == id)// filter the user by id
.findFirst()// if find then return the first
.orElseGet(User::new);// else return new User()
}
But it can be better to create a second query to get user by id :
private static final String SELECT_USERS_BY_ID = "select * from users_Alana WHERE id = ?1";
You need to return the User object from the getUser
public static User getUserById(int number) throws SQLException {
HashMap<Integer,User> getUser = new HashMap<Integer, User>();
return getUser.get(number);
}
You do need to populate the HashMap with the values though
I was trying to implement the query cache for large queries in ArangoDB.
When i check if the document cursor is cached or not, it shows that the cache is true. But i see no performance improvements in the query time processing.
However using the same query from arangodb web interface shows high performance improvements due to caching.
Edit :
Java Driver Version: 2.7.4
ArangoDb Version: 2.8.7
My Query is:
for t in MyStorage FILTER t.myDate>'2016-01-11' and t.myDate<'2016-06-01' and t.fraud!=null and t.fraud!='' and t.currency=='INR' return {myID:t.myID,myDate:t.myDate,amount:t.amount,fraud:t.fraud}
We tested Caching with the following Testcase and saw a performance improvement.
Can you post an example of your query?
public class ArangoDriverCacheTest {
private static final String COLLECTION_NAME = "unitTestCollection";
private static final String DATABASE_NAME = "unitTestDatabase";
private static ArangoConfigure configure;
private static ArangoDriver driver;
#BeforeClass
public static void setup() throws ArangoException {
configure = new ArangoConfigure();
configure.init();
driver = new ArangoDriver(configure);
// // create test database
try {
driver.createDatabase(DATABASE_NAME);
} catch (final ArangoException e) {
}
driver.setDefaultDatabase(DATABASE_NAME);
// create test collection
try {
driver.createCollection(COLLECTION_NAME);
} catch (final ArangoException e) {
}
driver.truncateCollection(COLLECTION_NAME);
// create some test data
for (int i = 0; i < 1000000; i++) {
final TestEntity value = new TestEntity("user_" + (i % 10), "desc" + (i % 10), i);
driver.createDocument(COLLECTION_NAME, value);
}
}
#AfterClass
public static void shutdown() {
try {
driver.deleteDatabase(DATABASE_NAME);
} catch (final ArangoException e) {
}
configure.shutdown();
}
private AqlQueryOptions createAqlQueryOptions(
final Boolean count,
final Integer batchSize,
final Boolean fullCount,
final Boolean cache) {
return new AqlQueryOptions().setCount(count).setBatchSize(batchSize).setFullCount(fullCount).setCache(cache);
}
#Test
public void test_withoutCache() throws ArangoException {
// set cache mode off
final QueryCachePropertiesEntity properties = new QueryCachePropertiesEntity();
properties.setMode("off");
driver.setQueryCacheProperties(properties);
exceuteQuery(false);
}
#Test
public void test_withCache() throws ArangoException {
// set cache mode on
final QueryCachePropertiesEntity properties = new QueryCachePropertiesEntity();
properties.setMode("on");
driver.setQueryCacheProperties(properties);
// set caching to true for the query
exceuteQuery(true);
}
private void exceuteQuery(final boolean cache) throws ArangoException {
final AqlQueryOptions aqlQueryOptions = createAqlQueryOptions(true, 1000, null, cache);
final String query = "FOR t IN " + COLLECTION_NAME + " FILTER t.age >= #age SORT t.age RETURN t";
final Map<String, Object> bindVars = new MapBuilder().put("age", 90).get();
DocumentCursor<TestEntity> rs = driver.executeDocumentQuery(query, bindVars, aqlQueryOptions, TestEntity.class);
// first time, the query isn't cached
Assert.assertEquals(false, rs.isCached());
final long start = System.currentTimeMillis();
// query the cached value
rs = driver.executeDocumentQuery(query, bindVars, aqlQueryOptions, TestEntity.class);
Assert.assertEquals(cache, rs.isCached());
// load all results
rs.asEntityList();
final long time = System.currentTimeMillis() - start;
System.out.println(String.format("time with cache=%s: %sms", cache, time));
}
private static class TestEntity {
private final String user;
private final String desc;
private final Integer age;
public TestEntity(final String user, final String desc, final Integer age) {
super();
this.user = user;
this.desc = desc;
this.age = age;
}
}
}