Boa tarde meus amigos, desenvolvi um método mais genérico de acordo com meu modelo e foi necessário fazer um casting do tipo downcasting, alguem pode me auxiliar ou indicar uma forma melhor que a minha ? Segue abaixo o código
public Atividade carregarAtividade(Integer idPessoa, Class<? extends Atividade> clazz) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<? extends Atividade> q = cb.createQuery(clazz);
Root<? extends Atividade> from = q.from(clazz);
q.where(cb.equal(from.get("pessoa"), idPessoa));
TypedQuery<? extends Atividade> typedQuery = em.createQuery(q);
try {
Atividade singleResult = typedQuery.getSingleResult();
return singleResult;
} catch (NoResultException ex) {
return null;
}
}
No caso, a hierarquia do meu modelo é a seguinte.
Interface Atividade
Cliente implements Atividade
Fornecedor implements Atividade
Na chamada do método precisei fazer o casting ficando do seguinte jeito
Cliente cli = (Cliente) pessoaDao.carregarAtividade(4731, Cliente.class);
Fornecedor f = (Fornecedor) pessoaDao.carregarAtividade(4731, Fornecedor.class);
Em teoria nunca vai dar erro, pois eu sei exatamente qual o tipo de atividade vai retornar, isso vai me trazer problemas ? Tem alguma forma melhor?
Grato desde já.
Você pode usar um type parameter para o tipo retornado, assim nao precisa do casting no final.
Basicamente mudaria a assinatura para:
public <T extends Atividade> T carregar(long id, Class<T> clazz)
E aí em todo lugar que você usa o “? extends Atividade” você troca por T
3 curtidas
E por que não usa generics, direto?
Funcionou perfeitamente Abel, muito obrigado !
1 curtida
No caso essa classe esta sendo gerenciada pelo container ejb, se ela fosse genérica eu teria que injetar um tipo genérico para cada atividade que eu precisasse buscar
Tem duas perguntas para você se fazer e analisar se essa estrutura está correta.
1 - Um cliente é uma atividade?
2 - Um fornecedor é uma atividade?
Quando você implementa uma interface ou estende uma classe, você está dizendo que sua classe é aquilo que ela implementa ou estende.
No seu exemplo, não me faz sentido um Cliente ser uma Atividade ou um Fornecedor ser uma Atividade
.
A meu ver, eles podem, ou não, exercer uma (ou mais) atividades.
Nesse caso você agrega Atividade com Cliente e Fornecedor.
Em meu modelo completo, na verdade uma Pessoa pode ter varias atividades, por exemplo ela por ter atividade de cliente, atividade de fornecedor, nesse caso seria mais intuitivo em vez de Cliente, seria AtividadeCliente que implementa uma atividade, voce teria alguma idéia boa para esse tipo de modelagem no jpa?
Ter e ser são diferentes.
Conceitualmente, na orientação a objetos, estes dois verbos abrem espaço para quatro conceitos (na prática dois, que possuem duas especializações): tem um, que se refere a composição e agregação e é um que se refere a herança e implementação.
O que o @staroski disse é extremamente importante. Sempre faça estas perguntas.
Com relação a como modelar, o JPA possui estruturas e ferramentas que atendem a praticamente tudo o que um banco de dados possibilita. Você só precisa analisar e identificar se o relacionamento de Cliente/Fornecedor é de um para um com atividades, de um para muitos, de muitos para um ou de muitos para muitos.
Vou falar como eu preciso no meu banco de dados
Pessoa -> ID - APELIDO - ENDEREÇO - CPNJ/CPF, ISCLIENTE,ISFORNECEDOR, ETC
CLIENTE -> ID - FORMA PAGAMENTO, PESSOA_ID
FORNECEDOR -> ID - FATURALIVRE, PESSOA_ID
CARREGADOR -> ID - VALORFIXO, PESSOA_ID
E é exatamente como esta, o problema era que eu precisava passar naquele meu método inicial carregarAtividade qualquer um desses tipos para não precisar criar vários métodos com o mesmo código, então implementei todos a uma mesma interface, acredito que mudando as nomenclaturas irá ficar mais coerente.
E onde está a atividade, neste exemplo?
Obs.: Forma de pagamento é um atributo relacionado a cliente ou a compra?
Forma de pagamento é o padrão do cliente para ser carregado na view no caso a venda.Cliente,Fornecedor,Carregador e etc são as atividades da pessoa, a Pessoa pode ter uma atividade de cliente, uma atividade de fornecedor, uma atividade de carregador.
Atividade não é algo que o cliente ou fornecedor executa? Por exemplo, o cliente realiza uma compra, não é uma atividade? O fornecedor realizou uma venda, entregou um pedido?
Creio que você esteja com dificuldades para construir o modelo de tua aplicação.
O cliente não realiza uma compra no sistema, quem vai gerenciar tudo é o Usuário que é um Funcionario da empresa, será um sistema interno.
O usuário lança uma venda para o cliente especifico, assim como ele lança uma compra para o fornecedor.
Indepentende de quem vai fazer, você vai registrar a venda ao cliente, vai registrar a NF que entrou e etc.
De qualquer forma, o sistema é teu, você faz da maneira que melhor convir.
Eu tenho um fornecedor que é cliente ao mesmo tempo, e vice-versa e também um representante comercial poderia ser um cliente, em resumo eu queria unificar o cadastro, assim o usuario não precisaria fazer dois cadastros individuais com os mesmos dados, vou fazer um modelo novo, assim voce poderá me auxiliar melhor.
Nada impede que isso seja feito, até é recomendado, para integridade dos dados no banco.
O que eu questionei foi quanto a uma atividade (que se refere à ação, no meu entendimento) estar sendo aplicada como perfil (que se refere ao que cada pessoa é, dentro do teu sistema).
Como eu te disse, no meu entendimento, eu jamais colocaria desta forma, mas, se você acha plausível e necessário, vá em frente.
Vamos ignorar por um instante a Atividade, segue abaixo o modelo original sem dizer que essas classes são uma atividade.
@Entity
public class Pessoa {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String nome;
@Column(unique = true)
@NotNull
@NotBlank(message = "Por favor, digite um apelido")
private String apelido;
@Embedded
private Endereco endereco;
@Temporal(TemporalType.TIMESTAMP)
private Calendar dataCadastro;
@Email(message = "Formato de email invalido!")
private String email;
private String fone;
private String cpf_cnpj;
private String razaoSocial;
private String ie;
private boolean cliente;
private boolean fornecedor;
private boolean carregador;
}
@Entity
public class Cliente {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@OneToOne
private Pessoa pessoa;
private String formaPagamento;
}
@Entity
public class Fornecedor {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@OneToOne
private Pessoa pessoa;
private String livre;
}
1 curtida
Veja que com estes códigos você está dizendo que:
Cliente tem uma pessoa
@Entity
public class Cliente {
@OneToOne
private Pessoa pessoa;
}
E fornecedor tem uma pessoa
@Entity
public class Fornecedor {
@OneToOne
private Pessoa pessoa;
}
Enquanto que, para o modelo que você deseja implementar, o mais assertivo seria fazer com que, tanto Cliente quanto Fornecedor fossem uma Pessoa:
@Entity
public class Fornecedor extends Pessoa {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String livre;
}
É lógico que o sistema irá funcionar se você utilizar a relação “tem um”, mas, no meu entender, o “é um” seria mais correto.
Edit: com essa abordagem, você ainda precisará definir algumas coisas no modelo, para que funcione adequadamente, mas, é a maneira mais simples que consigo ver.
1 curtida