I am facing a problem regarding populating bean objects from the resultset.
Description:Resultset contains the result of a stored procedure which is join of 3 tables B, BO, and BOV.
I have 3 POJO's corresponding to tables. The relation between tables is: B can have 0 or more BO's, BO can have 0 or more BOV's. So totally in resultset I have 162 records, which contain duplicates for B.
For example:
B BO BOV
1 1 1
1 1 2
1 2 1
2 1 1
and so on.
Actually there are 10 distinct B's. So II want only 10 B's from the resultset not 162 records. Also II should be able to get corresponding BO and BOV's like for B=1 all values of BO and BOV's.
How can I do this? This is pure java logic and cannot change anything for the stored procedure. Just have to process the resultset.
Have a running Map of the resultset here is a possible pseudocode
[pseudo code only... not guaranteed to compile]
Map mapofBs = new HashMap();
while(rs.hashNext()) {
rs.next();
String bId = rs.getString("columnname for id of b");
B objectB = mapofBs.get(bId);
if(objectB == null) {
objectB = new B();
//read relevant columns from result set and put into objectB
mapOfBs.put(bId, objectB)
}
//now onto the boId
String boId = rs.getString("columnname for id of BO");
BO objectBO = objectB.getBOForId(boId);
if(objectBO == null) {
objectBO = new BO();
//read relevat columns from result set for objectBO
objectB.addObjectBO(objectBO);
}
String bovID = s.getString("columnname for id of BOV");
BOV objectBOV = objectBO.getBOVForId(bovId);
if(objectBOV == null) {
objectBOV = new BOV();
//read relevat columns from result set for objectBOV
objectBO.addObjectBOV(objectBOV);
}
}
//mapOfBs.keySet() gives you a Set<B> which you are interested in
Changing the query to include a GROUP BY is much the best option.
Related
I have following table:
IDofDog, IDOfOwner
1 4
2 4
3 3
4 3
As you can see, one person can have more that one dogs. I also have a class:
class A{
int ownerID;
List <Integer> dogs;
}
Is it possible to get for chosen owner (for example 4) his dogs ? More exactly I would like (using mybatis) get such A a object that:
a.ownerID = 4
a.dogs = [1,2]
I think you might be able to do this with the #Result annotation. Something like...
interface DogRepo {
#Select("Select distinct IdOfOwner as ownerId from DogOwnership")
#Results(#Result(column = "ownerId", property = "dogs", many = #Many(select = "getDogIdsForOwner")))
A getDogsByOwner();
#Select("Select IdofDog from DogOwnership where IdOfOwner=#{ownerId}")
List<Integer> getDogIdsForOwner(#Param("ownerId") int ownerId);
}
Probably not the most efficient way of doing it, it might be more efficient to just read the rows and manually build up your objects.
I have following table People
I want to get relational records and make the JSON Array like following:
{ "Person":[
{"ID":1,
"FirstName":"James",
"LastName":"Donovan",
"Child":[
{"ID":6, "FirstName":"Nikolai", "LastName":"Donovan"}
]
},
{"ID":2,
"FirstName":"Jeffrey",
"LastName":"Williams",
"Child":[
{"ID":4, "FirstName":"Carol", "LastName":"Williams"},
{"ID":5, "FirstName":"Sarah", "LastName":"Williams"}
]
},
.... and so on
]
}
What I use following approach;
short summary of below code: I perform db operation twice in loop and put node into JSON Object is match certain conditions.
preparedStatement = con.prepareStatement("SELECT * FROM PEOPLE");
rs = preparedStatement.executeQuery(); // ResultSet Object
if (rs != null && rs.next()) {
Roles = new JSONObject();
parentNode = new JSONObject();
childNode = new JSONObject();
while(rs.next()) {
parentNode.put("ID", rs.getInt("Id"));
parentNode.put("FirstName", rs.getString("firstname"));
parentNode.put("LastName", rs.getString("lastname"));
if(rs.getInt("parent") > 0) { // Equal 0 Mean it has not child
// Perform again database operation and get record related to parent id
preparedStatement = con.prepareStatement("SELECT * FROM PEOPLE WHERE parent=?");
preparedStatement.setString(1, rs.getInt("id");
resultSet2 = preparedStatement.executeQuery();
while(resultSet2.next()) {
childNode.put("ID", rs.getInt("Id"));
childNode.put("FirstName", rs.getString("firstname"));
childNode.put("LastName", rs.getString("lastname"));
parentNode.put("Child":childRole); // put child into parent node
}
}
}
}
What I want?
Performing db select query in loop is too much expensive for server side.
Is there any better solution which generate desired JSON of relational data and save me from additional SELECT operations!
I am thankful for your attention!
If you are using mysql 5.7 you can you JSON_ARRAY function to create json array. or JSON_OBJECT https://dev.mysql.com/doc/refman/5.7/en/json-attribute-functions.html
maybe use two queries.
select blah where parent = 0.
select blah where parent != 0 order by parent, id
loop through the results of the second result set and assign them to the parent in the first result set.
use gson (or jackson or whatever json library you prefer) to convert from the object list to the final jason.
brief codelike stuff
select the parents (parent = 0).
for each parent row, add the row to a Map<String, Entity> where the key is the parent id.
select the children (parent != 0).
for each child row, get the parent row from the map using the parent id then add them to the parent entity.
use the same class for parent and child rows, initialize the child collection to null and create it on the first add of a child. This way, the child array will be included for parents that have children and not included for parents with no children and for children.
You could issue a single select
SELECT p.ID, p.FirstName, p.LastName, c.ID, c.FirstName, c.LastName
FROM PEOPLE p LEFT OUTER JOIN PEOPLE c ON c.parent = p.ID
ORDER BY p.ID
and then loop over the result.
Whenever the parent ID changes (and for the first result row) you build a new current parentNode. Then you read the child data (which may be empty in case the parent has no children) and put it into the child json array of the current parentNode.
In a text file the data is distributed like shown below, I am considering this as table for ease.
Column1 Column2 Column3 Column4
A B 1 2
A B 1 5
A C 1 3
B C 2 3
C A 3 4
A B 4 5
I need to cluster the the same values if column1 and column2 is same, like A->B is repeated 3 times combine like this.
A B 1 2
A B 1 5
A B 4 5
Here's how I would do it.
Define a class Record containing the 4 fields
Define a class RecordKey containing the identification of a row, i.e. the two first column values. Make sure equals and hashCode are properly defined.
Create a Map<RecordKey, List<Record>>.
Read the records line by line. If there is already a list in the map for the current record key, then add the current record to this list. Otherwise, create a new list, add the record to it, and put this list in the map.
Providing memory is not an issue then simply loading them into a List and then sorting them with those two columns as a compound key will cause them to cluster. I would suggest creating a simple class to store each record, then using list.sort(new Comparator<MyRecord>(){...});
The compare method will be fairly straightforward if you can be sure you have no nulls in your keys:
#Override
public int compare(MyRecord a, MyRecord b) {
int n = a.getFirst().compareTo(b.getFirst());
if (n == 0)
return a.getSecond().compareTo(b.getSecond());
return n;
}
If you can have nulls then you'll need to be a bit more careful and check for them
You can use this type of Map structure.
Map<String, Map<String, List<Record>>> parentMap
Record is a pojo in which you can store entire record.
public class Record {
private String column1;
private String column2;
private Integer column3;
private Integer column4;
//getter setter
}
And in map you can put like this.
Map<String, Map<String, List<Record>>> parentMap = new HashMap<String, Map<String,List<Record>>>();
Map<String, List<Record>> innerMap;
List<Record> innerList;
Record r;
for (Record loop) {
innerMap = parentMap.get(column1);
if (innerMap == null || innerMap.size() == 0) {
innerMap = new HashMap<String, List<Record>>();
parentMap.put(column1, innerMap);
}
innerList = innerMap.get(column2);
if (innerList == null || innerList.size() == 0) {
innerList = new ArrayList<Record>();
innerMap.put(column2, innerList);
}
r = new Record();
//set values in r
innerList.add(r);
}
I need to build a dynamic dataTable, which carry an object from the database with the following structure:
I need to build a dynamic dataTable, which carry an object from the database with the following structure:
Object:
Name = Ana
Cpf = 12364547
I need this data to be displayed in two columns, for example:
column 1
name
cpf
column 2
Ana
12364547
I have the following code:
public void criarTabelaDinamica(Object obj){
fc = FacesContext.getCurrentInstance();
this.tableMensagem = (HtmlDataTable) fc.getApplication().createComponent(HtmlDataTable.COMPONENT_TYPE);
HtmlColumn column1 = new HtmlColumn();
tableMensagem.getChildren().add(column1);
HtmlColumn column2 = new HtmlColumn();
tableMensagem.getChildren().add(column2);
tableMensagem.setValue(obj); //how to put the items in the two columns of the object? Here is my question!!!
}
note: The object varies on the amount of items in my example are 2, you may have 5 for example.
Thanks!!!
My Database Table Schema is something like
DocumentID: Name1: Name2: Name3: Name4: Location1: Location2: Location3....:Organization1:..
Now I have 3 Hashset's available having the above values (i.e one for name, one for location and one for organization)
In each single iteration of loop these hashset are being populated with above values.
At the end of each iteration the data from these hashset's is removed and new one's are created.
Now my problem is at each iteration I have to populate the sql table row (just 1 row each iteration) from these hashset values.
What I am not able to understand is if I have hard coded strings than simply I can use something like:
String sql = "INSERT INTO Table " +
"VALUES ('100', 'Zara', 'Akli', '18','100', 'Zara', 'Ali', '18')";
However I need to iterate through each hashset and insert (something like above) the data of all 3 hashset's in a single row. I am confused of how to write such statement. Remember my table is initially completely empty so I cant't use the where clause (something like "insert into.....where documentID="23423")
Assuming you have created these Sets these way:
long DocumentId
names {"A", "B", "C"}
location {"1", "2", "3"}
and so on...
I think the easiest is to build dinamically the SQL to execute:
{
...
StringBuilder sb = new StringBuilder("insert into mytable (");
List<Object> params = new ArrayList<Object>();
addColumnAndValue(sb, "DocumentID", docIdYouHaveSomewhere, params);
int i = 0;
for (String name: names)
addColumnAndValue(sb, ",name" + i, name, params);
i = 0;
for (String location: locations)
addColumnAndValue(sb, ",location" + i, location, params);
// now close the thing
sb.append(") values (?");
for (i = 1; i<params.size(); i++)
sb.append(",?");
sb.append("=");
// and now sb.toString() will contain valid SQL and the param values for a PreparedStatement will be in params array-list:
PreparedStatement ps = conn.prepareStatement(sb.toString());
for (i=0; i<params.size(); i++)
ps.setObject(i+1, params.get(i));
ps.executeUpdate(); // voi là!
...
}
private void add addColumnAndValue(StringBuilder sb, String columnName, Object value, List<Object> params) {
sb.append(columnName);
params.add(value);
}
i guess you need to first do some work on your 3 "HashSet"s.
Since you said the data in 3 Sets will finally go to single row in database. so I suggest that convert your 3 hashset into a Map, or at least a List, with same order as the fields in your insert statement. so that later you could set those values by name or index as parameters to your PS.
and I have never seen an insert statement like "Insert into table values (....) where id=123" are u sure it will work?