[RESOLVIDO] Lista não traz dados de classes não relacionadas

Olá pessoal.
Estou com dificuldades (mesmo depois de muito busca) para listar os dados realizando JOIN com mais duas tabelas, sendo que uma não tem a primeira não tem vínculo com a terceira.
Quero apresentar na lista a Cidade, Estado e País.
Sendo que:
Cidade se relaciona com Estado,
Estado se relaciona com País,
Cidade NÃO se relaciona com País.

Como posso fazer este campo ser apresentado?
Seguem meus códigos.

Classe Pais
public class Pais {

private int codigo;
private String nome;
private String sigla2;
private String codInternacional; //CODE TO CALLS - FOR EXEMPLE: BRAZIL +55;


public int getCodigo() {
	return this.codigo;
}
public void setCodigo(int codigo) {
	this.codigo = codigo;
}

public String getNome() {
	return nome;
}
public void setNome(String nome) {
	this.nome = nome;
}

public String getSigla2() {
	return sigla2;
}
public void setSigla2(String sigla2) {
	this.sigla2 = sigla2;
}

public String getCodInternacional() {
	return codInternacional;
}
public void setCodInternacional(String codInternacional) {
	this.codInternacional = codInternacional;
}

//CLASS CONSTRUCTOR;
public Pais() {
}
public Pais(int codigo){
	this.codigo = codigo;
}
public Pais(String nome){
	this.nome = nome;
}

//PRINT DATA IN THE CONSOLE;
public String imprimePais(){
	
	String dadosPais = "Dados do País: " +"\n";
			dadosPais += "Código: " + this.getCodigo() + "\n";
			dadosPais += "Nome: " + this.getNome() + "\n";
			dadosPais += "Sigla 2: " + this.getSigla2() + "\n";
			dadosPais += "Código Internacional: " + this.getCodInternacional() + "\n";
			
	return dadosPais;
}

}

Classe PaisDao
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import br.com.jdbc.ConnectionFactory;
import br.com.modelo.geo.Pais;

public class PaisDao {

private Connection connection;

public PaisDao() throws SQLException {
	this.connection = new ConnectionFactory().getConnection();
}

public void adiciona(Pais pais) {
	
	String sql = "INSERT INTO GEO.PAIS (NOME, SIGLA2, CODINTERNACIONAL) VALUES (?,?,?)";
	
	try {
		
		PreparedStatement stmt = connection.prepareStatement(sql);
		
		//stmt.setInt(1, pais.getCodigo()); THIS FIELD IS AUTO_INCREMMENT IN DATA BASE;
		stmt.setString(1, pais.getNome());
		stmt.setString(2, pais.getSigla2().toUpperCase());
		stmt.setString(3, pais.getCodInternacional());
		
		stmt.execute();
		stmt.close();
		
	} catch (SQLException e) {
		throw new RuntimeException(e);
		// TODO: handle exception
	}
}

public List<Pais> getLista(){

	try {
	
		List<Pais> paises = new ArrayList<Pais>();
	
		PreparedStatement stmt = this.connection.prepareStatement("SELECT P.CODIGO, P.NOME, P.SIGLA2, P.CODINTERNACIONAL FROM GEO.PAIS AS P;");
	
		ResultSet rs = stmt.executeQuery();
	
		while(rs.next()) {
			
			Pais pais = new Pais();
			pais.setCodigo(rs.getInt("CODIGO"));
			pais.setNome(rs.getString("NOME"));
			pais.setSigla2(rs.getString("SIGLA2"));
			pais.setCodInternacional(rs.getString("CODINTERNACIONAL"));
			
			paises.add(pais);
		}
			
			rs.close();
			stmt.close();
			return paises;
	
	} catch (SQLException e) {
			throw new RuntimeException(e);
	}
}

public void altera (Pais pais) {
	
	String sql = "UPDATE GEO.PAIS SET NOME=?, SIGLA2=?, CODINTERNACIONAL=? WHERE CODIGO=?;";
	
	try {
		PreparedStatement stmt = connection.prepareStatement(sql);
		
		stmt.setString(1, pais.getNome());
		stmt.setString(2, pais.getSigla2());
		stmt.setString(3, pais.getCodInternacional());
		stmt.setInt(4, pais.getCodigo());
		
		stmt.execute();
		stmt.close();
		
	} catch (SQLException e) {
		throw new RuntimeException(e);
	}
}

public void remove (Pais pais) {
	
	String sql = "DELETE FROM GEO.PAIS WHERE CODIGO=?";
	
	try {
		PreparedStatement stmt = connection.prepareStatement(sql);
		
		stmt.setInt(1, pais.getCodigo());
		
		stmt.execute();
		stmt.close();
		
	} catch (SQLException e) {
		throw new RuntimeException(e);
	}
}

}

Classe Estado
package br.com.modelo.geo;

public class Estado {

private int codigo;
private String nome;
private String sigla2;
private Pais pais;


public int getCodigo() {
	return codigo;
}
public void setCodigo(int codigo) {
	this.codigo = codigo;
}

public String getNome() {
	return nome;
}
public void setNome(String nome) {
	this.nome = nome;
}

public String getSigla2() {
	return sigla2;
}
public void setSigla2(String sigla2) {
	this.sigla2 = sigla2;
}

public Pais getPais() {
	return pais;
}
public void setPais(Pais pais) {
	this.pais = pais;
}

//CLASS CONSTRUCTOR;
public Estado() {
}

public Estado(int codigo){
	this.codigo = codigo;
}
public Estado(String nome){
	this.nome = nome;
}

//PRINT DATA IN THE CONSOLE;
public String imprimeEstado() {
	String dadosEstado = "Dados do Estado: ";
	dadosEstado += "Código: " + this.getCodigo();
	dadosEstado += "Nome: " + this.getNome();
	dadosEstado += "Sigla: " + this.getSigla2();
	dadosEstado += "País: " + this.getPais();
	return dadosEstado;
}

}

Classe EstadoDao
package br.com.dao.geo;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import br.com.jdbc.ConnectionFactory;
import br.com.modelo.geo.Estado;
import br.com.modelo.geo.Pais;

public class EstadoDao {

private Connection connection;

public EstadoDao() throws SQLException {
	this.connection = new ConnectionFactory().getConnection();
}

public void adiciona(Estado estado) {
	
	String sql = "INSERT INTO GEO.ESTADO (NOME, SIGLA2, PAIS) VALUES (?,?,?);";
	
	try {
	
		PreparedStatement stmt = this.connection.prepareStatement(sql);
		
		//stmt.setInt(1, estado.getCodigo()); THIS FIELD IS AUTO_INCREMMENT IN DATA BASE;
		stmt.setString(1, estado.getNome());
		stmt.setString(2, estado.getSigla2().toUpperCase());
		stmt.setInt(3, estado.getPais().getCodigo());
		
		stmt.execute();
		stmt.close();
		connection.close();
	
	} catch (SQLException e) {
		throw new RuntimeException(e);
	}
}

public List<Estado > getLista(){
	
	List<Estado> estados = new ArrayList<>();
	
	try {
		
		String sql = "SELECT E.CODIGO, E.NOME, E.SIGLA2, P.NOME  AS PAIS "
				+ "FROM GEO.ESTADO AS E "
				+ "JOIN GEO.PAIS AS P ON E.PAIS = P.CODIGO;";
	
		PreparedStatement stmt = this.connection.prepareStatement(sql);
		ResultSet rs = stmt.executeQuery();
		
		while(rs.next()) {
			
			Estado estado = new Estado();
			
			estado.setCodigo(rs.getInt("CODIGO"));
			estado.setNome(rs.getString("NOME"));
			estado.setSigla2(rs.getString("SIGLA2"));
			estado.setPais(new Pais(rs.getString("PAIS")));
			
			estados.add(estado);
		}
	
		rs.close();
		stmt.executeQuery();
		stmt.close();
		connection.close();
		
	} catch (SQLException e) {

		throw new RuntimeException(e);
	}
	
	return estados;
}

public void altera (Estado estado) {
	
	String sql = "UPDATE GEO.ESTADO SET NOME=?, SIGLA2=?, PAIS=? WHERE CODIGO=?";
	
	try {
	
		PreparedStatement stmt = this.connection.prepareStatement(sql);
		stmt.setString(1, estado.getNome());
		stmt.setString(2, estado.getSigla2());
		stmt.setInt(3, estado.getPais().getCodigo());
		stmt.setInt(4, estado.getCodigo());
		
		stmt.execute();
		stmt.close();
		connection.close();
		
	} catch (SQLException e) {

		throw new RuntimeException(e);
	}
}

public void remove(Estado estado) {
	String sql = "DELETE FROM GEO.ESTADO WHERE CODIGO=?";
	
	try {
	
		PreparedStatement stmt = this.connection.prepareStatement(sql);
		stmt.setInt(1, estado.getCodigo());
		
		stmt.execute();
		stmt.close();
		connection.close();
	
	} catch (SQLException e) {
		throw new RuntimeException(e);
	}
}

}

Classe Cidade
package br.com.modelo.geo;

public class Cidade {

private int codigo;
private String nome;
private Estado estado;


public int getCodigo() {
	return codigo;
}
public void setCodigo(int codigo) {
	this.codigo = codigo;
}

public String getNome() {
	return nome;
}
public void setNome(String nome) {
	this.nome = nome;
}

public Estado getEstado() {
	return estado;
}
public void setEstado(Estado estado) {
	this.estado = estado;
}

//CLASS CONSTRUCTOR;
public Cidade() {
}
public Cidade(int codigo){
	this.codigo = codigo;
}
public Cidade(String nome){
	this.nome = nome;
}

//PRINT DATA IN THE CONSOLE;
public String imprimeCidade() {
	String dadosCidade = "Dados da Cidade: ";
	dadosCidade += "Código: ";
	dadosCidade += "Nome: ";
	dadosCidade += "Estado: ";
	return dadosCidade;
}

}

Classe CidadeDao
package br.com.dao.geo;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import br.com.jdbc.ConnectionFactory;
import br.com.modelo.geo.Cidade;
import br.com.modelo.geo.Estado;
import br.com.modelo.geo.Pais;

public class CidadeDao {

private Connection connection;

public CidadeDao() throws SQLException {
	this.connection = new ConnectionFactory().getConnection();
}

public void adiciona (Cidade cidade) throws SQLException {
	
	String sql = "INSERT INTO GEO.CIDADE (NOME, ESTADO) VALUES (?,?);";
	
	try {
	
		PreparedStatement stmt = connection.prepareStatement(sql);
	
		// stmt.setInt(1, cidade.getCodigo()); THIS FIELD IS AUTO_INCREMMENT IN DATA BASE;
		stmt.setString(1, cidade.getNome());
		stmt.setInt(2, cidade.getEstado().getCodigo());
		
		stmt.execute();
		stmt.close();
	
	} catch (SQLException e) {
		throw new RuntimeException(e);
	}
}

public List<Cidade> gelista() {
	
	List<Cidade> cidades = new ArrayList<>();

	try {
	
	String sql = "SELECT C.CODIGO, C.NOME, E.NOME AS ESTADO, P.NOME AS PAIS "
			+ "FROM GEO.CIDADE AS C "
			+ "JOIN GEO.ESTADO AS E ON C.ESTADO = E.CODIGO "
			+ "JOIN GEO.PAIS AS P ON E.PAIS = P.CODIGO";
	
	PreparedStatement stmt = this.connection.prepareStatement(sql);
	ResultSet rs = stmt.executeQuery();
	
	while(rs.next()) {
		
		Cidade cidade = new Cidade();
		
		cidade.setCodigo(rs.getInt("CODIGO"));
		cidade.setNome(rs.getString("NOME"));
		cidade.setEstado(new Estado(rs.getString("ESTADO")));
		cidade.setEstado(new Estado(new Pais().getNome()));
		
		
		cidades.add(cidade);
		
	}
	
	rs.close();
	stmt.executeQuery();
	stmt.close();
	connection.close();

} catch (SQLException e) {
	
	throw new RuntimeException(e);
}
	
	return cidades;
}

public void altera(Cidade cidade) {
	
	String sql = "UPDATE GEO.CIDADE SET NOME=?, ESTADO=? WHERE CODIGO=?";
	
	try {
		
		PreparedStatement stmt = this.connection.prepareStatement(sql);
		
		stmt.setString(1, cidade.getNome());
		stmt.setInt(2, cidade.getEstado().getCodigo());
		stmt.setInt(3, cidade.getCodigo());
		
		stmt.execute();
		stmt.close();
		connection.close();
		
	} catch (SQLException e) {

		throw new RuntimeException(e);
	}
}

public void remove (Cidade cidade) {
	
	String sql = "DELETE GEO.CIDADE WHERE CODIGO=?;";
	
	try {
	
		PreparedStatement stmt = connection.prepareStatement(sql);
	
		stmt.setInt(1, cidade.getCodigo());
		
		stmt.execute();
		stmt.close();
		connection.close();
		
	} catch (SQLException e) {

		throw new RuntimeException(e);
	}
}

}

Classe ListaCidade
package br.com.main.geo;

import java.sql.SQLException;
import java.util.List;

import br.com.dao.geo.CidadeDao;
import br.com.modelo.geo.Cidade;

public class ListaCidade {

public static void main(String[] args) throws SQLException {

	CidadeDao dao = new CidadeDao();
	List<Cidade> cidades = dao.gelista();
	
	for(Cidade listaCidade : cidades) {
		System.out.println("CÓDIGO: " + listaCidade.getCodigo());
		System.out.println("NOME: " + listaCidade.getNome());
		System.out.println("ESTADO: " + listaCidade.getEstado().getNome());
		System.out.println("PAÍS: " + listaCidade.getEstado().getPais().getNome() + "\n");
	}
}

}

E este é o erro que apresenta quando executo o ListaCidade
CÓDIGO: 0
NOME: SÃO PAULO
ESTADO: null
Exception in thread “main” java.lang.NullPointerException
at br.com.main.geo.ListaCidade.main(ListaCidade.java:20)

Ajudem-me a encontrar o erro… Por favor.
Por que não está trazendo o nome do Estado?
Por que não consigo trazer o nome do País?

Obrigado.

…Não e atentei que era SQLServer…Foi mal!

Fala ai marlonmsilva boa tarde,

cara um observação com relação a forma como foi constituído esse código
Atualmente voce esta colocando como:

Cidade Possui Estado que Possui Pais

acredito que o “mais correto” semanticamente seria o inverso

Pais possui Estado possui Cidade

public class Pais {
private int codigo;
private String nome;
private String sigla2;
private String codInternacional;
private Estado estado

public class Estado
private int codigo;
private String nome;
private String sigla2;
private Cidade cidade;

public class Cidade {
private int codigo;
private String nome;

Agora com relação ao erro NullPointerException é relacionado ao fato de vc não ter inicializado as demais classes atraves dos construtores ou seja,

no construtor de Cidade voce deveria ter

public Cidade() {
estado = new Estado()
}

no construtor de Estado voce deveria ter:

public Estado() {
pais = new Pais()
}

Abraços
Max

@FacaNaCaveira, tudo bem?
Antemão, muito obrigado pela dica e ajuda.

Ainda não consegui fazer rodar. Porém, os erros são menos alarmantes que antes.
Veja, por favor, como ficou o código com suas dicas e como está sendo o retorno.

Vou postar somente as alterações.

Classe CidadeDao
public List gelista() {

	List<Cidade> cidades = new ArrayList<>();

	try {
	
	String sql = "SELECT C.CODIGO AS CODIGO, C.NOME AS CIDADE, E.NOME AS ESTADO, P.NOME AS PAIS "
			+ "FROM GEO.CIDADE AS C "
			+ "JOIN GEO.ESTADO AS E ON C.ESTADO = E.CODIGO "
			+ "JOIN GEO.PAIS AS P ON E.PAIS = P.CODIGO";
	
	
	PreparedStatement stmt = this.connection.prepareStatement(sql);
	ResultSet rs = stmt.executeQuery();
	
	while(rs.next()) {
		
		Cidade cidade = new Cidade();
		
		cidade.setCodigo(rs.getInt("CODIGO"));
		cidade.setNome(rs.getString("CIDADE"));
		cidade.setEstado(new Estado(rs.getString("ESTADO")));
		cidade.setEstado(new Estado(new Pais(rs.getString("PAIS"))));
		
		cidades.add(cidade);
		
		
	}
	
	rs.close();
	stmt.executeQuery();
	stmt.close();
	connection.close();

} catch (SQLException e) {
	
	throw new RuntimeException(e);
}
	
	return cidades;
}

Classe Estado
//CLASS CONSTRUCTOR;
public Estado() {
}

public Estado(int codigo){
	this.codigo = codigo;
}

public Estado(String nome){
	this.nome = nome;
}

public Estado(Pais pais) {
	this.pais = new Pais();
}

Classe Cidade
//CLASS CONSTRUCTOR;
public Cidade() {
}

public Cidade(int codigo){
	this.codigo = codigo;
}

public Cidade(String nome){
	this.nome = nome;
}

public Cidade(Estado estado) {
	estado = new Estado();
}

Este é o retorno obtido quando rodo a classe ListaCidade.
Estado e País estão vindo null.

CÓDIGO: 1
NOME: CIDADE 1
ESTADO: null
PAÍS: null

CÓDIGO: 2
NOME: CIDADE 2
ESTADO: null
PAÍS: null

CÓDIGO: 3
NOME: CIDADE 3
ESTADO: null
PAÍS: null

Explica melhor isso aqui ?

É a famosa orientação a objetos que ensinam.

Ué, explica ?

Explicar o que exatamente? De problema, a segunda linha anula a primeira.

hummmm, aqui temos uma evolução na conversa :wink:

Show de bola.
Já entendi que a segunda linha está anulando a primeira.
Mas, gentilmente, gostaria do apoio na resolução.
Quanto a POO de hoje em dia, estou iniciando nos estudos agora. Desculpem não dominar ainda.

Alguém me sugere um código em que eu possa obter as informações no List?
Lembrando que no DB:
Cidade faz parte de um Estado;
Estado faz parte de um País.

O Google já tem essa solução pronta, tenta fazer uma pesquisa, se não conseguir pode voltar aqui novamente que a gente , te ajuda :wink:

String sql = "SELECT C.CODIGO AS CODIGO, C.NOME AS CIDADE, E.NOME AS ESTADO, P.NOME AS PAIS "
			+ "FROM GEO.CIDADE AS C "
			+ "JOIN GEO.ESTADO AS E ON C.ESTADO = E.CODIGO "
			+ "JOIN GEO.PAIS AS P ON E.PAIS = P.CODIGO";

Se essa é a resposta que precisa exibir pro usuário, cria uma classe que represente exatamente esse resultado, diretamente com os nomes, da Cidade, Estado, Pais, etc, simples assim, sem complicações de modelo OO.

Pra isso , é necessário uma base em Orientação a Objetos, você esta repetindo tudo o que ele já fez , a pergunta é sobre lista , então precisamos focar nisso , ele tem um Data Acess Object pra persistência e quer que a lista invoque os dados , parte da solução esta nesse link Veja se ajuda

Sim, só é mais complicado, muitas voltas para atender uma funcionalidade simples.

Tem que ver um todo pra entender um simples, não adianta um pedaço de código livre no espaço, existe uma visão maior é por isso que Design Patters são usados pra dar abstração ,o link que postei coloca ele em uma visão mais detalhada é nisso que precisamos fazer quando alguém não compreende o que faz:wink:

Tem razão. O ideal seria ele mostrar um protótipo do que precisa atender, só código deixa a questão com mil possibilidades.

Sobre abstração, sou contra a abstrair o que não é necessário.

Quando não é macro como um projeto , você tem plataforma e design pra uma arquitetura a resolver isso você recorre a padrão de projetos(Design Patter) , no cenário abortado poderíamos ter um simples UML para uma representação de seus objetos , não cai em contradição o que mostrei foi uma implementação de Lista e o que poderia se fazer em um projeto Swing Java, não precisamos fazer novatos ficarem adivinhando soluções sem base pra discutir , assuntos de implementação.:wink:

Entendo sua visao, cada um escolhe seus meios. Mas pela minha experiencia, pra exibir uma informação pro usuário que está em um bd relacional nunca foi necessário UML.

1 curtida

Veja só os requisitos aqui são puramente de implementação, a UML é um design pra o modelo relacional, sim concordo com você quando estamos entendendo uma especialização de lista , mas o que você coloca é fora do contexto e simplesmente uma chamada de consulta mas isso também é representável em um diagrama de classe ,seu conceito é algo como eu estivesse no Linux e digita-se List para ver os diretórios, no Eclispe temos os metadados que estão a representação gráfica de diretório e arquivos.

Pessoal…
Muito obrigado a todos pelo apoio.
Resolvido com uma pequena alteração no código…

public List<Cidade> gelista() {
	
	List<Cidade> cidades = new ArrayList<>();

	try {
	
	String sql = "SELECT C.CODIGO AS CODIGO, C.NOME AS CIDADE, E.NOME AS ESTADO, P.NOME AS PAIS "
			+ "FROM GEO.CIDADE AS C "
			+ "JOIN GEO.ESTADO AS E ON C.ESTADO = E.CODIGO "
			+ "JOIN GEO.PAIS AS P ON E.PAIS = P.CODIGO";
	
	
	PreparedStatement stmt = this.connection.prepareStatement(sql);
	ResultSet rs = stmt.executeQuery();
	
	while(rs.next()) {
		
		Cidade cidade = new Cidade();
		
		cidade.setCodigo(rs.getInt("CODIGO"));
		cidade.setNome(rs.getString("CIDADE"));
		cidade.setEstado(new Estado(rs.getString("ESTADO")));
		cidade.getEstado().setPais(new Pais(rs.getString("PAIS"))); // Linha alterada.
		
		cidades.add(cidade);
		
		
	}
	
	rs.close();
	stmt.executeQuery();
	stmt.close();
	connection.close();

} catch (SQLException e) {
	
	throw new RuntimeException(e);
}

Precisava somente pegar o Estado, setar o País e pegar o resultado do seu nome.
Quanto a ideia de criar outra classe só para consolidar o resultado de uma lista, não acho que seria válido, tendo em vista possuir: o modelo, o DAO e o main. Outro main, na minha opnião exclusivo para isso, não faz sentido.
Mas como disse, ainda estou estudando.

Mais uma vez, obrigado a todos.