JPA com Hibernate fazendo INNER JOIN

Boa tarde a todos!

Eu tenho uma tela de cadastro de Empresas, que possui um campo que denomina
a atividade da empresa chamado ramo_atividade.
Tenho a entidade Atividade que possui apenas código e descrição somente.
Fiz o cadastro normalmente colocando um combo com as atividades possíveis.
Gravo o código da atividade no campo ramo_atividade, beleza.
Agora eu preciso fazer uma listagem de empresas. Nesta listagem vai aparecer a atividade de cada empresa, e cada
empresa só tem uma atividade.
Eu estou usando JSF e JPA/Hibernate.
Como eu faço para trazer os dados das empresas com a descrição da atividade de cada uma?
Nas minhas classes Empresa e Atividade não fiz nenhum relacionamento tipo ManyToOne, OneToOne.
Na minha classe Empresa não trouxe o objeto Atividade. A minha entidade empresa só possui um campo
chamado tipo_atividade que está gravando o código da atividade.
Estou tentando fazer um inner join para trazer e descrição da atividade das empresas mas não está dando certo.
Eu devo fazer todo o procedimento, como por exemplo trazer na entidade Empresa o objeto Atividade, colocando o tipo
de relacionamento também e tudo mais, ou consigo apenas fazer trazer a descrição da atividade de cada empresa na base do inner join mesmo?
É necessário dizer que este relacionamento é simples, quero dizer que o codigo da atividade na tabela empresa não entra como
foreing key, mas é um campo obrigatório.
Obrigado!

Pelo que entendi, você não usou joins para referenciar suas tabelas, particularmente eu acho isso uma ótima pratica, pois deixa seu banco mais rápido, já que os dados de uma tabela não estão vinculados ou dependentes de outras tabelas, inclusive foi isso que me vez querer mudar para NoSQL, “não existe” necessidade deles se relacionares com chaves estrangeiras. Pois você monta seu relacionamento na aplicação, o que é muito mais rápido para execução.
Com isso, fica claro que se você não relacionar seus dados no banco, você terá que de alguma forma relaciona-los na aplicação. Existe duas formas de se fazer isso: 1° você pode escrever sql que referenciam para você antes de passar para o banco. 2° Como você esta usando hibernate, você pode usar criteria.

Para referenciar duas tabelas sem foreing key, você pode usar a seguinte lógica. “-Se cada empresa tem um id único, e cada atividade pertence a uma unica empresa, então porque não colocar uma coluna na tabela atividades que receba o id da empresa? E escrever um sql que traga as atividades em que o valor dessa coluna seja igual ao valor do identificador da minha empresa.” Literalmente eu digo setar o id da empresa nesse campo da atividade, mas sem as anotações @OneToMany ou @OneToOne.
Se em algum momento você precisar de @ManyToMany, então realmente irá necessitar de uma terceira tabela para isso, mas é claro sem essas anotações, sempre utilizando uma lógica java e sql na sua aplicação, nunca no banco de dados.
Qualquer duvida, coloca ai o seu código, para entendermos melhor.

Olá Rodrigo, obrigado por responder!

A única ressalva que faço é que pode haver duas empresas com a mesma atividade.
O que vejo de diferente neste caso é que é diferente por exemplo de uma conta e sua movimentação.
O relacionamento neste caso é forte. Num curso da Caelum mostra que temos que importar o objeto Conta na hora
de gravar as movimentações.
No caso da Empresa e sua Atividade, a Atividade apenas é um campo obrigatório.
Será que mesmo assim tenho que na hora de criar a Entidade Empresa (POJO) eu tenho que declarar o objeto Atividade nele,
ou não faço nada e na hora da de eu montar a consulta é só usar Critéria para mostrar a descrição da atividade?
É isso que eu quero entender. Na OO qualquer caso de código que sua descrição está em outra tabela, eu tenho que
declará-lo na classe que possui o código!!!
Obrigado!

Nos bancos de dados relacionais, “todas” as tabelas devem ter a coluna id. A chave primaria é obrigatório, não tem jeito. Isso é para uma melhor pratica de estrutura de dados. Leia este post depois [JPA] Tabelas sem chave primária.
No seu caso, se cada empresa pode ter mais de uma atividade, então você pode ‘inverter a referencia’. Como os id são obrigatório, você cria uma coluna na tabela empresa chamada idAtividade e coloca id da atividade desejada. Com isso, você pode ter duas ou muito mais empresas, em que no campo idAtividade, esta o id 25 (que se refere a atividade 25). É claro, de alguma forma você tem que referenciar na sua aplicação. Tipo, antes de salvar a atividade, você já tem que ter identificado a empresa. Isso são coisas comuns que envolve algumas técnicas e praticas de programação. Eu por exemplo, colocaria o id da empresa na sessão de um pagina que esta logada. Pois assim, ao salvar uma nova atividade, eu já referencio o numero do id da atividade nas empresas que tem o id da sessão. Se for mais de uma empresa, então não se pode usar sessão, logo você terá que buscar todos os ids referentes e criar uma lista para persistir no banco. Igual como se estivesse identificando uma lista de emails ou contas de amigos no facebook.

Só dois detalhes, se uma atividade pode se referenciar a mais de uma empresa e uma empresa pode ter varias atividades, então você precisa de no minimo três tabelas para isso, com apenas três campos: idTabela que é obrigatório, mais a coluna idEmpresa, e outra coluna referente ao idAtividade relacionada.

E outro detalhe, é que nesse caso você tem que identificar o id da atividade antes de salva-lo no banco, ou seja, o id da tabela atividade deve ser gerado na aplicação. Uma solução concatenar toda uma data(o próprio facebook faz isso). ano+mês+dia+hora+minutos+segundos+milisegundos ou então só

Long idAtividade1=new Date().getTime() // ou Long idAtividade2=System.currentTimeMillis();

Das duas formas o valor nunca vai se repetir. A menos que sejam executados no momento de milisegundos exatos. Mas para evitar isso concatena um numero sorteado entre 1 e 10 mil. Veja um exemplo para dois ids executados quase no mesmo instante e como eles pode ser salvos no banco:

public static void main(String[] args) {
	long t1=System.currentTimeMillis();
	long t2=System.currentTimeMillis();
	System.out.println(t1);
	System.out.println(t2);
	int valor1=(int)(Math.random()*10000+10000);
	int valor2=(int)(Math.random()*10000+10000);
	Long idAtividade1=Long.parseLong(new Date().getTime()+""+valor1);
	Long idAtividade2=Long.parseLong(new Date().getTime()+""+valor2);
	System.out.println("valor1: "+valor1);
	System.out.println("valor2: "+valor2);
	System.out.println("idAtividade1: "+idAtividade1);
	System.out.println("idAtividade2: "+idAtividade2);
}

Inicialmente parece complicado e desvantajoso, mas isso é o que o banco faria se você usasse relacionamentos diretos(@OneToMany, etc…), com a diferença que teria uma estrutura diretamente vinculada a outra, o que complica diversas operações nos bancos, além de deixa-lo lento com tantas tabelas ‘ligadas’ as outras.
Bom faça seus próprios testes e tire suas próprias conclusões.

Ok Rodrigo, obrigado pelos seus comentários! Boa semana!