How to get data from SQL with sql2o? - java

I'm trying to get data from mySQL to List in java using sql2o lib.
But for some reason I just fail to understand how to use it properly (it looks like).
Here is the faulty code:
List<String> returning = new ArrayList<String>();
String date = "";
String playerList = "";
String playerCount = "";
String playerMax = "";
con.createQuery(sql)
.throwOnMappingFailure(true).addColumnMapping("date", date)
.addColumnMapping("playerList", playerList)
.addColumnMapping("playerCount", playerCount)
.addColumnMapping("playerMax", playerMax).executeAndFetch(String.class);
returning.add(date);
returning.add(playerList);
returning.add(playerCount);
returning.add(playerMax);
And here is error I get:
org.sql2o.Sql2oException: Could not map date to any property.
at org.sql2o.DefaultResultSetHandlerFactory.newResultSetHandler0(DefaultResultSetHandlerFactory.java:199)
at org.sql2o.DefaultResultSetHandlerFactory.access$200(DefaultResultSetHandlerFactory.java:17)
at org.sql2o.DefaultResultSetHandlerFactory$5.evaluate(DefaultResultSetHandlerFactory.java:160)
at org.sql2o.DefaultResultSetHandlerFactory$5.evaluate(DefaultResultSetHandlerFactory.java:156)
at org.sql2o.tools.AbstractCache.get(AbstractCache.java:49)
at org.sql2o.DefaultResultSetHandlerFactory.newResultSetHandler(DefaultResultSetHandlerFactory.java:173)
at org.sql2o.PojoResultSetIterator.<init>(PojoResultSetIterator.java:20)
at org.sql2o.Query$14.iterator(Query.java:547)
at org.sql2o.Query.executeAndFetch(Query.java:588)
at org.sql2o.Query.executeAndFetch(Query.java:574)
at lol.discordbot.database.QueryServerInfo.getCurrent(QueryServerInfo.java:31)
at lol.discordbot.command.Query.execute(Query.java:20)
at lol.discordbot.command.CommandsListener.onMessageReceived(CommandsListener.java:39)

I think you misunderstand what column mappings are. Column mappings are used to map column names to object-field names.
You should first create a data class to hold the result of your query. From your code above, I assume that you are trying to fetch players.
public class Player {
public String date;
public String playerList;
public String playerCount;
public String playerMax
}
(Consider to use better data types. Date for dates, int for counts, etc)
Then you can use sql2o to fetch data
List<Player> players = con.createQuery(sql).executeAndFetch(Player.class);

There is a much better way now.
.setAutoDeriveColumnNames(true)
Example
try (Connection con = sql2o.open()) {
List<Player> l = con.createQuery(sql)
.setAutoDeriveColumnNames(true)
.executeAndFetch(Player.class);
}
https://groups.google.com/g/sql2o/c/3H4XJIv-i04

Related

How to access and read the values of child objects of an object?

Here is how I am constructing an Object inside a method:
//right after creating the class
public static ArrayList<Object> old_devicelist = new ArrayList<Object>();
//inside a method
Date date = new Date();
long time = date.getTime();
Integer opened = 0;
String deviceId = "";
String dev_rssi = "";
Object[] MyObject = new Object[]{time, opened, deviceId, dev_rssi};
old_devicelist.add(MyObject);
Now, I would like to loop through that ArrayList and access some elements (note that deviceId might at some point contain an object and I would like to access id field of it) inside it, then I would like to use them like this, for ex. :
if(device.id == 33){
//do something...
}
You're using an array with type Object and then you're storing these object arrays into a list. This makes it hard to retrieve the information later.
Consider this instead:
public static List<Device> DEVICES = new ArrayList<>();
class Device {
Date date;
long time;
Integer opened;
String deviceId;
String deviceRssi
Device(Date date, Integer opened, String deviceId, String deviceRssi) {
this.date = date;
this.time = date.getTime();
this.opened = opened;
this.deviceId = deviceId;
this.deviceRssi = deviceRssi;
}
}
Device first = new Device(
new Date(),
0,
"",
"");
DEVICES.add(first);
System.out.println(DEVICES.get(0).deviceId);
...
for (Device device : DEVICES) {
if (device.deviceId.equals("33)) {
// ...
}
}
I'd recommend not using too many static/global variables and reading about the Java Naming Convention.
I guess you should create new class instead of using Object.
public class DeviceSpecification { //or any other name
long time;
Integer opened;
String deviceId;
String dev_rssi;
public DeviceSpecification(long time, Integer opened, String deviceId, String dev_rssi) {
this.time = time;
this.opened = opened;
this.deviceId = deviceId;
this.dev_rssi = dev_rssi;
}
}
Create a list with specific type:
public static List<DeviceSpecification> oldDeviceCollection = new ArrayList<>();
Create an instance of a class
DeviceSpecification device = new DeviceSpecification(new Date().getTime(), 0, "", "")
Add the instance to a list
oldDeviceCollection.add(device);
Use it in query - we can use streams from Java 8
oldDeviceCollection.stream()
.forEach(
device -> {
if(device.id.equals("33")) {
// do something
}
);
First of all your Arraylist takes Objects and you are trying to add an Object array so if your goal is to keep object arrays with the device_id you should change your Arraylist to
public static ArrayList<Object[]> old_devicelist = new ArrayList();
Taking that in mind you can access any deviceid by typing
old_devicelist.get(i)[2]
where i is the element you want and 2 because you have setted device_id to be the 3rd element of your Object array!
Hope this helps!

Perform select of data from multiple tablea using JDBC template

I need to perfom a select by date from my DB in my spring boot webapp. What I have so far is a list of sport competitions and there respective informations.
Problem : I can not figure out how my select query convert my String type (dateFrom = '2017-05-02' and dateTo = '2017-05-06') to date like '2017-02-12' in the ?
Alos how to fill my RowMapper with more then one date in some competition which have more then one date.
My data base schema:
CREATE TABLE competition (
competition_id integer PRIMARY KEY,
nom varchar(128) NOT NULL,
);
CREATE TABLE date (
id integer PRIMARY KEY,
date_time timestamptz,
competition_id integer REFERENCES competition (competition_id)
);
Json data:
{
"id": "420",
"name": "SOCCER",
"dates": [
"2016-05-12T03:00:00.000Z"
"2016-05-12T04:00:00.000Z"
"2016-05-12T05:00:00.000Z"
]
},
{
"id": "220",
"name": "BASKETBALL",
"dates": [
"2016-05-12T03:00:00.000Z"
"2016-05-12T04:00:00.000Z"
]
}
My competition Class:
public class Competition{
private int id;
private String name;
private String[] dates;
// setters ... getters
}
My RowMapper Class:
public class RowMapper implements RowMapper
{
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Competition competition = new Competition();
competition.setId(rs.getInt("id"));
competition.setName(rs.getString("name"));
competition. // How to fill dates
return competition;
}
}
Function to select data :
private static final String SELECT_STMT =
" select * from competition INNER JOIN date ON
+ " competition.competition_id = date.competition_id"
+ " WHERE date(date.date_time) BETWEEN ? AND ?"
;
public List<Competition> findByOptionsAll(String dateFrom, String dateTo ){
List<Competition> competitions = jdbcTemplate.query(SELECT_STMT, new
RowMapper(), dateFrom, dateTo);
return competitions ;
}
Date converting
Right now you have all dates as a String both in your DB and domain model. To convert strings to date you need a date formatter:
private static final String DATE_FORMAT = "dd-MM-yy";
// parsing date; Note you should handle ParseException
java.util.Date date = new SimpleDateFormat(DATE_FORMAT).parse(dateAsString);
// converting date to string
String dateAsString = new SimpleDateFormat(DATE_FORMAT).format(date);
Note that SimpleDateFormat is not thread-safe so it's a good practice to have static final String DATE_FORMAT instead of static final DateFormatter
Converting date and time is tricky in some cases (what about time zone? java.util.Date vs joda.time vs LocalDate from Java 8) but out of scope. I suggest use LocalDate if possible just because it's a new way without old issues.
Mapping
You have two entities in your DB (Competition and Date-of-competition) and only one class Competition in your domain model. Most probably, later you'll want to add additional info to the Date-of-competition (boolean finished, cancelled, Score etc) so it's a good idea to create CompetitionInstance class right now.
Since you have One-to-Many relationship you have to write some additional stuff to map objects. Normally that's what an ORM like Hibernate do istead of you. First, add a 'GROUP BY competition_id' in your sql statement.
Then use RowSetExtractor instead of RowMapper as described here:
private static final class CompetitionMapExtractor implements ResultSetExtractor<List<Competition>> {
#Override
public List<Competition> extractData(ResultSet rs) throws SQLException {
List<Competition> result = new ArrayList<>(rs.getCount());
int previousCompetitionId = NEVER_EXIST; // normally -1 is good enough
while (rs.next()) {
// we have some dates with the same competition_id
// dates are grouped thanks to GROUP BY clause
if ( rs.getInt("id") != previousCompetitionId) {
Competition currentCompetition = new Competition(rs.getInt("id"),
rs.getString("name");
/* I prefer constructor initializers "o = new O(propertyValue)"
instead of snippet "o = new O(); o.setProperty(value)"
*/
result.add(currentCompetition);
previousCompetitionId = currentCompetition.getid();
} else {
currentCompetition.addDate(new CompetitionInstance(rs.getString("date")));
}
}
return result;
}
I suppose Competition has method public void addDate(String date) which simply add a new CompetitionInstance to a list.
Update:
1.
column name in DB and in MapExtractor is different. I prefer to change the query:
SELECT c.id, c.name, d.date_time as date
from competition c
INNER JOIN date d ON c.competition_id = d.competition_id
WHERE date(d.date_time) BETWEEN ? AND ?"
2. I can't reproduce issues you have with date. Most probably you mixed up java.util.Date, java.sql.Date and java.sql.Timestamp - this is a common mistake. There are many answers already, probably you could find one of them useful.

Mapping several columns from sql to a java object

I am trying to retrieve and process code from JIRA, unfortunately the pieces of information (which are in the Metadata-Plugin) are saved in a column, not a row.
Picture of JIRA-MySQL-Database
The goal is to save this in an object with following attributes:
public class DesiredObject {
private String Object_Key;
private String Aze.kunde.name;
private Long Aze.kunde.schluessel;
private String Aze.projekt.name;
private Long Aze.projekt.schluessel
//getters and setters here
}
My workbench is STS and it's a Spring-Boot-Application.
I can fetch a List of Object-Keys with the JRJC using:
JiraController jiraconnect = new JiraController();
List<JiraProject> jiraprojects = new ArrayList<JiraProject>();
jiraprojects = jiraconnect.findJiraProjects();
This is perfectly working, also the USER_KEY and USER_VALUE are easily retrievable, but I hope there is a better way than to perform
three SQL-Searches for each project and then somehow build an object from all those lists.
I was starting with
for (JiraProject jp : jiraprojects) {
String SQL = "select * from jira_metadata where ENRICHED_OBJECT_KEY = ?";
List<DesiredObject> do = jdbcTemplateObject.query(SQL, new Object[] { "com.atlassian.jira.project.Project:" + jp.getProjectkey() }, XXX);
}
to get a list with every object, but I'm stuck as i can't figure out a ObjectMapper (XXX) who is able to write this into an object.
Usually I go with
object.setter(rs.getString("SQL-Column"));
But that isn't working, as all my columns are called the same. (USER_KEY & USER_VALUE)
The Database is automatically created by JIRA, so I can't "fix" it.
The Object_Keys are unique which is why I tried to use those to collect all the data from my SQL-Table.
I hope all you need to enlighten me is in this post, if not feel free to ask for more!
Edit: Don't worry if there are some 'project' and 'projekt', that's because I gave most of my classes german names and descriptions..
I created a Hashmap with the Objectkey and an unique token in brackets, e.g.: "(1)JIRA".
String SQL = "select * from ao_cc6aeb_jira_metadata";
List<JiraImportObjekt> jioList = jdbcTemplateObject.query(SQL, new JiraImportObjektMapper());
HashMap<String, String> hmap = new HashMap<String, String>();
Integer unique = 1;
for (JiraImportObjekt jio : jioList) {
hmap.put("(" + unique.toString() + ")" + jio.getEnriched_Object_Key(),
jio.getUser_Key() + "(" + jio.getUser_Value() + ")");
unique++;
}
I changed this into a TreeMap
Map<String, String> tmap = new TreeMap<String, String>(hmap);
And then i iterated through that treemap via
String aktuProj = new String();
for (String s : tmap.keySet()) {
if (aktuProj.equals(s.replaceAll("\\([^\\(]*\\)", ""))) {
} else { //Add Element to list and start new Element }
//a lot of other stuff
}
What I did was to put all the data in the right order, iterate through and process everything like I wanted it.
Object hinfo = hmap.get(s);
if (hinfo.toString().replaceAll("\\([^\\(]*\\)", "").equals("aze.kunde.schluessel")) {
Matcher m = Pattern.compile("\\(([^)]+)\\)").matcher(hinfo.toString());
while (m.find()) {
jmo[obj].setAzeKundeSchluessel(Long.parseLong(m.group(1), 10));
// logger.info("AzeKundeSchluessel: " +
// jmo[obj].getAzeKundeSchluessel());
}
} else ...
After the loop I needed to add the last Element.
Now I have a List with the Elements which is easy to use and ready for further steps.
I cut out a lot of code because most of it is customized for my problem.. the roadmap should be enough to solve it though.
Good luck!

Return records in java

I need to return multiple records in to a variable, in below mention code with in while loop I am getting all the records but while return result I am getting only one record I don't know how to do
public String feed()
{
String projectname=null;
String claintid=null;
String projectstatus=null;
String prjstartdate=null;
String prjenddate=null;
String lastmodified=null;
String prjpinurl=null;
String patientDetails=null;
try
{
Connection conn = getMySqlConnection();
String simpleProc = "{ call Sp_RetPrjvals () }";
CallableStatement cs = conn.prepareCall(simpleProc);
ResultSet rs=(ResultSet) cs.executeQuery();
while(rs.next()){
projectid=rs.getString(1);
projectname=rs.getString(2);
claintid=rs.getString(3);
projectstatus=rs.getString(4);
prjstartdate=rs.getString(5);
prjenddate=rs.getString(6);
lastmodified=rs.getString(7);
prjpinurl=rs.getString(8);
patientDetails=projectid+"|"+projectname+"|"+claintid+"|"+projectstatus+"|"+prjstartdate+"|"+prjenddate+"|"+lastmodified+"|"+prjpinurl;
//here i am getting two values before:::2|Sample project 2|1|WIP|2015-08-01 00:00:00.0|2016-08-01 00:00:00.0|2015-08-24 16:40:10.0|http://hcup-us.ahrq.gov/toolssoftware/ccs/ccs.jsp
before:::1|Sample project 1|1|WIP|null|null|2015-08-24 16:38:39.0|http://hcup-us.ahrq.gov/toolssoftware/ccs/ccs.jsp
}
conn.close();
} catch (Exception e)
{
}
return patientDetails;
// here i am getting only After:::1|Sample project 1|1|WIP|null|null|2015-08-24 16:38:39.0|http://hcup-us.ahrq.gov/toolssoftware/ccs/ccs.jsp
}
The problem is that you override your String. You have to add it to a list or an array.
For example: List<String> al = new ArrayList<String>()
and then you have to add the String you build on every while step into this array and retrun this array:
al.add(patientDetails);
your return statement follows this: return al;
your function header is then:
public List<String> feed(){
patientDetails is a `String` Object.
If you expet to be able to retun a list of striong, then you should use an array of String objects in that case.
Something like:
String[] patientDetails
Then in your code you should add each returned record to your array
Something like:
patientDetails[i] = projectid+"|"+projectname+"|"+claintid+"|"+projectstatus+"|"+prjstartdate+"|"+prjenddate+"|"+lastmodified+"|"+prjpinurl;
i ++; //Initialize this *i* variable outside the while
Also change the signature of your method as:
public String[] feed()
Because you don't know your result size, you need a dynamic structure, like a list:
List<String> pacients = new ArrayList<>();
while(results.next()){
...
String patientDetails = ....;
pacients.add(patientDetails);
}
After this code you will have alist of pacient details. But I would advise you to keep their data in an object, not a String;
class PatientDetails {
String projectname; // you don't have to initialize with null, it's done by default
String claintid;
String projectstatus;
String prjstartdate;
String prjenddate;
String lastmodified;
String prjpinurl;
String patientDetails;
// getters & setters
#Override
public String toString(){
return projectid+"|"+projectname+"|"+claintid+"|"+ ...;
}
}
Now when you will want to print a PatientDetails you will get same result as your string representation.
And you would return a List<PatientDetails> holding your query results.

Java Storing Multiple Rows From Select Queries

This is actually a re-do of an older question of mine that I have completely redone because my old question seemed to confuse people.
I have written a Java program that Queries a database and is intended to retrieve several rows of data. I have previously written the program in Informix-4GL and I am using a sql cursor to loop through the database and store each row into a "dynamic row of record". I understand there are no row of records in Java so I have ended up with the following code.
public class Main {
// DB CONNECT VARIABLE ===========================
static Connection gv_conn = null;
// PREPARED STATEMENT VARIABLES ==================
static PreparedStatement users_sel = null;
static ResultSet users_curs = null;
static PreparedStatement uinfo_sel = null;
static ResultSet uinfo_curs = null;
// MAIN PROGRAM START ============================
public static void main(String[] args) {
try {
// CONNECT TO DATABASE CODE
} catch(Exception log) {
// YOU FAILED CODE
}
f_prepare(); // PREPARE THE STATEMENTS
ArrayList<Integer> list_id = new ArrayList<Integer>();
ArrayList<String> list_name = new ArrayList<String>();
ArrayList<Integer> list_info = new ArrayList<String>();
ArrayList<String> list_extra = new ArrayList<String>();
try {
users_sel.setInt(1, 1);
users_curs = users_sel.executeQuery();
// RETRIEVE ROWS FROM USERS
while (users_curs.next()) {
int lv_u_id = users_curs.getInt("u_id");
String lv_u_name = users_curs.getString("u_name");
uinfo_sel.setInt(1, lv_u_id);
uinfo_curs = uinfo_sel.executeQuery();
// RETRIEVE DATA FROM UINFO RELATIVE TO USER
String lv_ui_info = uinfo_curs.getString("ui_info");
String lv_ui_extra = uinfo_curs.getString("ui_extra");
// STORE DATA I WANT IN THESE ARRAYS
list_id.add(lv_u_id);
list_name.add(lv_u_name);
list_info.add(lv_ui_info);
list_extra.add(lv_ui_extra);
}
} catch(SQLException log) {
// EVERYTHING BROKE
}
// MAKING SURE IT WORKED
System.out.println(
list_id.get(0) +
list_name.get(0) +
list_info.get(0) +
list_extra.get(0)
);
// TESTING WITH ARBITRARY ROWS
System.out.println(
list_id.get(2) +
list_name.get(5) +
list_info.get(9) +
list_extra.get(14)
);
}
// PREPARE STATEMENTS SEPARATELY =================
public static void f_prepare() {
String lv_sql = null;
try {
lv_sql = "select * from users where u_id >= ?"
users_sel = gv_conn.prepareStatement(lv_sql);
lv_sql = "select * from uinfo where ui_u_id = ?"
uinfo_sel = gv_conn.prepareStatement(lv_sql)
} catch(SQLException log) {
// IT WON'T FAIL COZ I BELIEEEVE
}
}
}
class DBConn {
// connect to SQLite3 code
}
All in all this code works, I can hit the database once, get all the data I need, store it in variables and work with them as I please however this does not feel right and I think it's far from the most suited way to do this in Java considering I can do it with only 15 lines of code in Informix-4GL.
Can anyone give me advice on a better way to achieve a similar result?
In order to use Java effectively you need to use custom objects. What you have here is a lot of static methods inside a class. It seems that you are coming from a procedural background and if you try to use Java as a procedural language, you will not much value from using it. So first off create a type, you can plop it right inside your class or create it as a separate file:
class User
{
final int id;
final String name;
final String info;
final String extra;
User(int id, String name, String info, String extra)
{
this.id = id;
this.name = name;
this.info = info;
this.name = name;
}
void print()
{
System.out.println(id + name + info + extra);
}
}
Then the loop becomes:
List<User> list = new ArrayList<User>();
try {
users_sel.setInt(1, 1);
users_curs = users_sel.executeQuery();
// RETRIEVE ROWS FROM USERS
while (users_curs.next()) {
int lv_u_id = users_curs.getInt("u_id");
String lv_u_name = users_curs.getString("u_name");
uinfo_sel.setInt(1, lv_u_id);
uinfo_curs = uinfo_sel.executeQuery();
// RETRIEVE DATA FROM UINFO RELATIVE TO USER
String lv_ui_info = uinfo_curs.getString("ui_info");
String lv_ui_extra = uinfo_curs.getString("ui_extra");
User user = new User(lv_u_id, lv_u_name, lv_ui_info, lv_ui_extra);
// STORE DATA
list.add(user);
}
} catch(SQLException log) {
// EVERYTHING BROKE
}
// MAKING SURE IT WORKED
list.get(0).print();
This doesn't necessarily address the number of lines. Most people who use Java don't interact with databases with this low-level API but in general, if you are looking to get down to the fewest number of lines (a questionable goal) Java isn't going to be your best choice.
Your code is actually quite close to box stock JDBC.
The distinction is that in Java, rather than having a discrete collection of arrays per field, we'd have a simple Java Bean, and a collection of that.
Some examples:
public class ListItem {
Integer id;
String name;
Integer info;
String extra;
… constructors and setters/getters ellided …
}
List<ListItems> items = new ArrayList<>();
…
while(curs.next()) {
ListItem item = new ListItem();
item.setId(curs.getInt(1));
item.setName(curs.getString(2));
item.setInfo(curs.getInfo(3));
item.setExtra(curs.getString(4));
items.add(item);
}
This is more idiomatic, and of course does not touch on the several frameworks and libraries available to make DB access a bit easier.

Categories