I am working on a Java assignment that requires pulling languages from a COUNTRY_LANGS_SQL table, then using a loop to display the Country, Population, Median Age, and Language(s) for each country. I'm able to display the 4 Countries, Population, Median Age, but for the life of me I cannot figure out what statement I need to declare in order for it to pull and loop the languages in. I've tried numerous variations with no success, so I'm hoping someone can take a look and point out what I'm doing wrong. Any help would be greatly appreciated.
UPDATE 3: So I'm very close to having this working now with it successfully executing and displaying language column, it's just not displaying the languages of the country (see below)
Name: Canada Population: 34568211 Median Age: 41.5 ID : 1 Language: []
Name: Germany Population: 81147265 Median Age: 45.7 ID : 2 Language: []
Name: South Africa Population: 49601098 Median Age: 25.5 ID : 3 Language: []
Name: Japan Population: 127253075 Median Age: 45.8 ID : 4 Language: []
I also only have one error now in the readLanguages method
"
The method getId() is undefined for the type List
"
/**
* #return list of countries read from the country database
*/
public List<Country> getCountries() {
return countries;
}
private void readLanguages() {
try (
Connection connection = getConnection();
PreparedStatement stmt = connection.prepareStatement(GET_COUNTRY_LANGS_SQL)
) {
for (Country country : countries); {
stmt.setInt(0, countries.getId());
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
int i = 0;
countries.get(i).addLanguage(rs.getString("language"));
rs.close();
}
}}
catch (SQLException e) {
System.err.println("ERROR: " + e.getMessage());
e.printStackTrace();
}
It seems to not be pulling the Id's from the Country class, or it's not looping correctly. Any thoughts?
1)CountriesDB.java
package edu.pcc.cis233j.countries;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Read data from the countries database
*
* #author
*/
public class CountriesDB {
private static final String DB_NAME = "Countries";
private static final String DB_URL = "jdbc:jtds:sqlserver://cisdbss.pcc.edu/" + DB_NAME;
private static final String USERNAME = "";
private static final String PASSWORD = "";
private static final String GET_COUNTRIES_SQL = "SELECT * FROM COUNTRY";
private static final String GET_COUNTRY_LANGS_SQL = "SELECT * FROM COUNTRY_LANGUAGE WHERE CountryId = ?";
private List<Country> countries;
/**
* Create a CountriesDB object
* Read from the Countries database and populate the countries list
*/
public CountriesDB() {
countries = readCountries();
}
/**
* Create and return a connection to the database
* #return connection to the countries database
*/
private Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
return connection;
}
/**
* Read country info from the Country table.
* If an error occurs, a stack trace is printed to standard error and an empty list is returned.
* #return the list of countries read
*/
private List<Country> readCountries() {
List<Country> countries = new ArrayList<>();
try (
Connection connection = getConnection();
PreparedStatement stmt = connection.prepareStatement(GET_COUNTRIES_SQL);
ResultSet rs = stmt.executeQuery()
) {
while (rs.next()) {
countries.add(new Country(rs.getInt("Id"),
rs.getString("Name"),
rs.getLong("Population"),
rs.getDouble("MedianAge")));
}
}
catch (SQLException e) {
System.err.println("ERROR: " + e.getMessage());
e.printStackTrace();
}
return countries;
}
/**
* #return list of countries read from the country database
*/
public List<Country> getCountries() {
return countries;
}
private void readLanguages() {
try (
Connection connection = getConnection();
PreparedStatement stmt = connection.prepareStatement(GET_COUNTRY_LANGS_SQL)
) {
for (Country country : countries); {
stmt.setInt(0, countries.getId());
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
int i = 0;
countries.get(i).addLanguage(rs.getString("language"));
rs.close();
}
}}
catch (SQLException e) {
System.err.println("ERROR: " + e.getMessage());
e.printStackTrace();
}
}
}
2)Country.java
package edu.pcc.cis233j.countries;
import java.util.ArrayList;
import java.util.List;
/**
* A country in the world
* #author Your Name & Cara Tang
*/
public class Country {
private int id;
private String name;
private long population;
private double medianAge;
private List<String> language = new ArrayList<>();
/**
* Create a Country object with the given properties
*/
public Country(int id, String name, long population, double medianAge) {
this.id = id;
this.name = name;
this.population = population;
this.medianAge = medianAge;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public long getPopulation() {
return population;
}
public double getMedianAge() {
return medianAge;
}
public List<String> getLanguage() {
return language;
}
public void addLanguage(String string) {
language.add(string);
}
}
3) CountryMain.java
package edu.pcc.cis233j.countries;
import java.util.List;
/**
* Read from the Country database and print data on the countries
* #author TJ
*/
public class CountryMain {
public static void main(String[] args) {
CountriesDB cdb = new CountriesDB();
List<Country> countries = cdb.getCountries();
for (Country country : countries) {
System.out.println("Name: " + country.getName()
+ " Population: " + country.getPopulation()
+ " Median Age: " + country.getMedianAge()
+ " ID : " + country.getId()
+ " Language: " + country.getLanguage()
);
}
}
}
First, the lines:
countries.add(new Country(rs.getString("Language"),
rs.getString("Language")));
refer to rs before it is declared or populated. Also, they appear to be trying to build a Country from two strings (both the same).
Second,
countries.add(new Language ());
Is crazy because countries has Country objects in it, so you can't just add a Language object, and a new one at that (not from the database).
It's almost as if you didn't write the code yourself and consequently don't understand it...
I think what you need is closer to this:
private void readLanguages() {
try (
Connection connection = getConnection();
PreparedStatement stmt = connection.prepareStatement(GET_COUNTRY_LANGS_SQL)
) {
ResultSet rs = null;
for (Country country : countries); {
stmt.setInt(1, country.getId());
rs = stmt.executeQuery();
while (rs.next()) {
country.setLanguage(rs.getString("Language")); //assumes 1 per country - others are discarded
}
rs.close();
}
}
}
not perfect java - but should give you an idea where you are going wrong.
Other notes:
The easy way to do this (assuming one language per country) would be to join the tables in the SELECT.
You should also close your database connection when finished with it.
I'm not sure that your try (stuff) {statements} syntax is correct.
If there are multiple languages per country, you need that supported in your data structures/classes.
I'm assuming your Country class has getters and setters for the fields.
Note: the question has been updated but I think this is still mostly relevant.
As by design, one Country can have multiple Languages, so your model should look like:
class Country {
private int id;
private String name;
private List<String> language;
//....
}
There are different ways you can construct it, most straight-forward one is something like (in pseudo-code):
List<Country> resultCountries=....;
countryRows = executeGetCountrySql
foreach countryRow in countryRows {
id = row.get("ID");
name = row.get("NAME");
List<String> langs = new ArrayList<();
langRows = executeGetLanguageByCountryIdSql(id);
foreach langRow in langRows {
langs.add(langRow.get("LANGUAGE"));
}
resultCountries.add(new Country(id, name, langs));
}
Some DB iirc does not allow concurrent resultsets. One way you can do is to read all countries first, and loop through each country and get its corresponding languages, and set it back to country.
Another way is to join the country table with country_language, and construct new country / add new language to existing country for each result row.
Related
guys, i stuck into the middle on process writing my own first web-app. I have a couple issues with DAO layer.
Look at my first entity:
public class Fabric {
private Integer id;
private String name;
private String country;
}
There is Object, which "id" property is the foreign key for another entity:
public class Guitar {
private Integer id;
private Fabric fabric;
private String name;
private Short strings;
private Color color;
private Integer count;
}
So when i try to write DAO layer for "Guitar" entity like this:
Guitar guitar = null;
try (Connection connection = ConnectionManager.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(GET_BY_ID)) {
preparedStatement.setInt(1, id);
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
guitar = Guitar.builder()
.id(resultSet.getInt(id))
***.fabric()*** <---- idk how to get fabric id
.name(resultSet.getString("name"))
.strings(resultSet.getShort("strings"))
.color(???some jave code???) <--- this is ENUM :(
.count(resultSet.getInt("count"))
.build();
}
} catch (SQLException e) {
throw new DaoException(e);
}
return Optional.ofNullable(guitar);
} ``
SQL request: ```private static final String GET_BY_ID = "SELECT id, fabric_id, name, strings, color, count FROM shop_storage.guitar WHERE count NOTNULL";
p.s. also idk how to get enum in this object:(
If can help me - i'll appreciate it.
have a good time anyone:)
I am interested in using Hibernate INNER JOINS that return an entity/model result.
At Hibernate Community Documentation, they write:
Or - assuming that the class Family has an appropriate constructor - as an actual typesafe Java object:
select new Family(mother, mate, offspr)
from DomesticCat as mother
join mother.mate as mate
left join mother.kittens as offspr
For the life of me, I have not been able to build that appropriate constructor. I want to query
Select new Participant(part, addr.adddressType)
from Participant part
INNER JOIN part.adddresses addr
Should I create a new Java class, let's say Participant_Address.java that reads like this:
Select new Participant_Address (part, addr.adddressType)
from Participant part
INNER JOIN part.adddresses addr
With constructor:
public Participant_Address(new Participant(...), String addressType)
Got this to work! Very happy..
Created a new class:
Placed in my Hibernate folder just for convenience/relevance:
package echomarket.hibernate;
public class ParticipantAddress implements java.io.Serializable {
private Participant part;
private String addressType;
public ParticipantAddress() {
}
public ParticipantAddress(Participant part, String addressType) {
this.part = part;
this.addressType = addressType;
}
public Participant getPart() {
return part;
}
public void setPart(Participant part) {
this.part = part;
}
public String getAddressType() {
return addressType;
}
public void setAddressType(String addressType) {
this.addressType = addressType;
}
}
Tested with:
package echomarket.hibernate;
import echomarket.hibernate.HibernateUtil;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class TestHib {
public static void main(String[] args) {
Session session = null;
Transaction tx = null;
List result = null;
String query = null;
try {
session = HibernateUtil.getSessionFactory().getCurrentSession();
tx = session.beginTransaction();
try {
query = "SELECT new echomarket.hibernate.ParticipantAddress(part, addr.addressType) "
+ " from Participant part "
+ " INNER JOIN part.addresses addr "
+ " WHERE addr.addressType = 'primary' AND part.participant_id = '603aec80-3e31-451d-9ada-bc5c9d75b569' GROUP BY part.participant_id, addr.addressType";
System.out.println(query);
result = session.createQuery(query)
.list();
tx.commit();
} catch (Exception e) {
System.out.println("Error result/commit in TestHib");
e.printStackTrace();
tx.rollback();
} finally {
tx = null;
session = null;
}
/// typically check that result is not null, and in my case that result.size() == 1
echomarket.hibernate.ParticipantAddress hold = (echomarket.hibernate.ParticipantAddress)result.get(0);
Participant pp = (Participant) hold.getPart(); /// Got my Participant record
System.out.println("wait"); /// put a break here so I could evaluate return on result, hold and pp
}
}
I really hope that this helps folks...
I am using Spring MVC with JdbcTemplate and a MySQL database.
Say I have the following 2 tables :
table_school
ID NAME
table_students
ID NAME ADDRESS SCHOOL_ID
I have a School POJO that has the following class variables :
int id, String name, List<Student> students
Is there a way of retrieving a List with each School object containing the appropriate List of Student objects using JdbcTemplate in one query? I know this is easily achievable using Hibernate but I would like to use JdbcTemplate ..
Many thanks !
Yes, you can fetch all data in 1 query.
Simple example:
class Student {
int id;
String name;
String addr;
Student(int id, String name, String addr) {
this.addr = addr;
this.id = id;
this.name = name;
}
}
class School {
int id;
String name;
List<Student> students = new ArrayList<>();
School(int id, String name) {
this.id = id;
this.name = name;
}
void addStudent(Student s) {
students.add(s);
}
}
/*
* helper method that gets school from map or create if not present
*/
private School getSchool(Map<Integer, School> schoolMap, int id, String name) {
School school = schoolMap.get(id);
if (school == null) {
school = new School(id, name);
schoolMap.put(id, school);
}
return school;
}
// RUN QUERY
String sql =
" select st.ID, st.NAME, st.ADDRESS. s.id, s.name" +
" from table_students st" +
" inner join table_school s on st.school_id = s.id";
final Map<Integer, School> schoolMap = new HashMap<>();
jdbcTemplate.query(sql, new RowCallbackHandler() {
#Override
public void processRow(ResultSet rs) throws SQLException {
int studentId = rs.getInt(1);
String studentName = rs.getString(2);
String studentAddr = rs.getString(3);
int schoolId = rs.getInt(4);
String schoolName = rs.getString(5);
Student student = new Student(studentId, studentName, studentAddr);
getSchool(schoolMap, schoolId, schoolName).addStudent(student);
}
});
One final point regarding fetching performance:
If you expect many records to fetch it is nearly always a good idea to increase jdbc fetch size parameter. So before run query set it on your jdbcTemplate:
jdbcTemplate.setFetchSize(200); // you can experiment with this value
or if you are using spring's JdbcDaoSupport you can use such pattern:
public class MyDao extends JdbcDaoSupport {
....
#Override
protected void initTemplateConfig() {
getJdbcTemplate().setFetchSize(200);
}
}
I'm making a mysql database connector with java to show all the data.
When I run the code, I get an NullPointerException in my getData() function.
here is my code.
public String[][] getData() {
String values[][];
try {
rs = st.executeQuery("SELECT * FROM adresses");
int i = 0;
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String adress = rs.getString("email_adress");
String catagory = rs.getString("catarogy");
values[i][0] = id;
values[i][1] = name;
values[i][2] = adress;
values[i][3] = catagory;
i++;
}
return values;
} catch (SQLException e) {
e.printStackTrace();
return values;
}
}
When the value of the String values is nothing I get The error. But if I give the String allready a value it says nothing .
public String[][] getData() {
String values[][] = {{"","","",""},
{"","","",""},
{"","","",""},};
try {
rs = st.executeQuery("SELECT * FROM adresses");
int i = 0;
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String adress = rs.getString("email_adress");
String catagory = rs.getString("catarogy");
values[i][0] = id;
values[i][1] = name;
values[i][2] = adress;
values[i][3] = catagory;
i++;
}
return values;
} catch (SQLException e) {
e.printStackTrace();
return values;
}
}
I want more data than that in my data String. how can I let it automatically do that??
Tnx.
PS.
The function is called in my class FrameGUI and has to change to Object
public class FrameGUI extends JFrame {
public JTable dataHolder;
Mysql mysql = new Mysql();
public String[] columnNames = {
"ID", "Name", "Adress", "Catagory"
};
-> public Object[][] data = mysql.getData();
public FrameGUI() {
init();
mysql.getData();
}
}
You do not initialize String values[][] so it is null. You either need to initialize it first or use a more appropriate datastructure like a List.
You should define a class and use a List (e.g. the ArrayList) instead.
e.g. if you want to call it User -
public class User {
private String id;
private String name;
//...
}
and a list
List<User> users = new ArrayList<User>();
and then instantiate the User class for each row and add the new instance to the list -
User currUser = new User();
users.add(currUser);
//set values from result set
The list can grow automatically when needed and the code is much more readable than using the array.
You get an index out of bounds in the first example because a String[][] (or String Matrix) gets initialized as a zero-length array.
In the second instance, you initialized the array to a size of 3x4 - that works so long as you only get 3 results back.
What you really need is a data structure with a dynamic size. Arrays aren't automatically sized dynamically. Try using a collection implementation like ArrayList or LinkedList or Vector.
Also, instead of saving your values to a String[], try creating a bean class that can hold your result. Create a new instance of it for each result that you get back instead of initializing a new array.
Because you didn't initialized your array, that is why you get NPE. Actually I suggest you to use List for your purposes:
public ArrayList<ArrayList<String>> getData() {
ArrayList<ArrayList<String>> values = new ArrayList<>();
try {
rs = st.executeQuery("SELECT * FROM adresses");
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String adress = rs.getString("email_adress");
String catagory = rs.getString("catarogy");
ArrayList<String> list = new ArrayList<>();
list.add(id);
list.add(name);
list.add(adress);
list.add(catagory);
values.add(list);
}
return values;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
}
The main problem in you code is you are using arrays to save variable number of data. Arrays is fixed sized after they are created so you can't add (or remove) elements to them dynamically.
Instead of using arrays you should use an ArrayList object which have methods to add more elements. Also instead of creating a multidimensional array it looks like a better idea to create a class for the data you get from you database.
So lets first create a Address class:
public class Address {
public String id, name, adress, catagory;
public Address(String id, String name, String adress, String catagory) {
this.id = id;
this.name = name;
this.adress = adress;
this.catagory = catagory;
}
}
Now you can write you code as:
public List<Address> getData() {
List<Address> values = new ArrayList<Address>();
try {
rs = st.executeQuery("SELECT * FROM adresses");
int i = 0;
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
String adress = rs.getString("email_adress");
String catagory = rs.getString("catarogy");
values.add(new Address(id, name, adress, catagory));
}
return values;
} catch (SQLException e) {
e.printStackTrace();
return values;
}
}
The returned list will contain a list of Address objects which have the values from you database. Also, the size of the list is always the same as the content you put into it.
Hi while developing one of my web application i am storing the user information in to an ArrayList based on sql query executed, it contain duplicate objects how to remove duplicate objects in list , i already tried some method but it still not working.
This Is My Code Correct me where i am wrong
public ArrayList loadData() throws ClassNotFoundException, SQLException {
ArrayList userList = new ArrayList();
String url = "";
String dbName = "";
String userName = "";
String password = "";
Connection con = null;
Class.forName("org.apache.derby.jdbc.ClientDriver");
con = DriverManager.getConnection(url + dbName, userName, password);
PreparedStatement ps = null;
try {
String name;
String fatherName;
int Id;
String filePath;
int age;
String address;
String query = "SELECT NAME,FATHERNAME,AGE,ADDRESS,ID,FILEPATH FROM USER_INFORMATION ,USER_PHOTO WHERE ID=USER_ID";
ps = con.prepareStatement(query);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
name = rs.getString(1);
fatherName = rs.getString(2);
age = rs.getInt(3);
address = rs.getString(4);
Id = rs.getInt(5);
filePath=rs.getString(6);
/* if(flag)
{
prev=Id;
flag=false;
}
else if(Id==prev)
{
TEMP=TEMP+";"+filePath;
}*/
//PhotoList = PhotoList(Id, con);
UserData list = new UserData();
list.setName(name);
list.setFatherName(fatherName);
list.setAge(age);
list.setAddress(address);
list.setId(Id);
// list.setFilePath(filePath);
userList.add(list);
}
ps.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
ArrayList al = new ArrayList();
HashSet hs = new HashSet();
hs.addAll(userList);
al.clear();
al.addAll(hs);
return al;
}
And My Bean Class contant is
public class UserData {
private String name;
private String fatherName;
private int Id;
//private String filePath;
private int age;
private String address;
public UserData()
{
}
public UserData(String name, String fatherName,int Id, int age,String address)
{
this.name = name;
this.fatherName = fatherName;
this.Id = Id;
//this.filePath=filePath;
this.age=age;
this.address=address;
}
//GETTER AND SETTER..
General Idea: Use Set, not List. But you must override hash and equals of the class.
If you want a Collection of objects that does not have a specific order and you don't want duplicates, it's better for you just to use a Set like for example HashSet, or, if in your set the order is important, the TreeSet.
Just remember to override the hash and equals methods.
if you add this to your bean everything should work:
public int hashCode() {
return (name + fatherName+ Id + filePath + age + address).hashCode();
}
public boolean equals(Object obj) {
return ( hashCode() == obj.hashCode() );
}
Your userdata class does not implement equals or hashcode. This means two instances created with the same values will not be counted as duplicates. This is why the set contains duplicates.
For example
UserData u1 = new UserData("Foo", "bar",1, 1,"baz");
UserData u2 = new UserData("Foo", "bar",1, 1,"baz");
u1 and u2 are not considered equal as they are different objects. Adding an equals and hashcode method should fix this. However even better is adarshr's idea of removing dupes in the SQL.
All duplicates must be removed at an SQL level. Your SQL is suggesting that it could be generating duplicate records.
String query = "SELECT NAME,FATHERNAME,AGE,ADDRESS,ID,FILEPATH FROM USER_INFORMATION ,USER_PHOTO WHERE ID=USER_ID";
What does the clause ID = USER_ID mean? Shouldn't you be passing in that value as an input to your query?
Also, is the column ID a primary key? Otherwise, use a where clause that doesn't generate duplicates.