Quando implementei meu tcc (um sistema desktop para uma empresa de Confecções) não sei por que, vi a necessidade de criar um Framework para me ajudar nesta árdua tarefa e uma das funcionalidades era justamente uma classe para manipular listas de uma forma que achei bem bacana.
Neste sistema, utilizei o JPA. Optei por não usar o Hibernate por não conhecer e também porque queria mesmo ter trabalho.
Utilizando o Netbeans e o JPA, temos a opção de criar “entidades do banco de dados”. Isto é muito útil pois será gerado inteiramente de “grátis” , as classes com todos os atributos da tabela e seus relacionamentos. Daí pra frente, é só separar os homens dos meninos e fazer as coisas segundo os mandamentos de implementação de equals() e hashCode().
Criei uma classe que herda de List, chamada hummm…List. Assim, dentro das minhas classes de dados, eu troco a declaração do pacote List do java, apontando para o meu pacote.
Utilizando o engine do JPA, temos muito a ganhar. Como exemplo, temos as querys que são geradas automaticamente, chamadas de namedquerys, que são pré-compiladas quando o contexto é iniciado, nos dando aumento de performance quando executadas. Também, é mantido um contexto onde ficam guardadas as refências de objetos que já estão gerenciados (vieram do banco e estão em memória) diminuindo a quantidade de acessos ao banco, dependendo de como está a arquitetura do seu sistema.
Depois de trazidos do banco para a memória, uso um tipo de Comparator para coisas como executar um where, ordenação da lista por campos especificos de cada objeto, tirar uma media de valores ou saber quem é maior ou menor.
Abaixo, coloco as classes de dados.
<code>//imports *
import orquestralist.list.List;</code>
/**
*
* @author marciliosouza
*/
@Entity
@Table(name = "cliente")
@NamedQueries({
@NamedQuery(name = "Cliente.findAll", query = "SELECT c FROM Cliente c"),
@NamedQuery(name = "Cliente.findByIdcliente", query = "SELECT c FROM Cliente c WHERE c.idcliente = :idcliente"),
@NamedQuery(name = "Cliente.findByCnpjcpf", query = "SELECT c FROM Cliente c WHERE c.cnpjcpf = :cnpjcpf"),
@NamedQuery(name = "Cliente.findByIerg", query = "SELECT c FROM Cliente c WHERE c.ierg = :ierg"),
@NamedQuery(name = "Cliente.findByDatacad", query = "SELECT c FROM Cliente c WHERE c.datacad = :datacad"),
@NamedQuery(name = "Cliente.findByLimite", query = "SELECT c FROM Cliente c WHERE c.limite = :limite")})
public class Cliente implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "idcliente")
private Integer idcliente;
@Basic(optional = false)
@Column(name = "cnpjcpf")
private String cnpjcpf;
@Basic(optional = false)
@Column(name = "ierg")
private String ierg;
@Basic(optional = false)
@Column(name = "datacad")
@Temporal(TemporalType.TIMESTAMP)
private Date datacad;
@Basic(optional = false)
@Column(name = "limite")
private long limite;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "cliente")
private List vendaList;
public Cliente() {
}
//gets sets
}
//imports...
/**
*
* @author marciliosouza
*/
@Entity
@Table(name = "produto")
@NamedQueries({
@NamedQuery(name = "Produto.findAll", query = "SELECT p FROM Produto p"),
@NamedQuery(name = "Produto.findByIdproduto", query = "SELECT p FROM Produto p WHERE p.idproduto = :idproduto"),
@NamedQuery(name = "Produto.findByDescricao", query = "SELECT p FROM Produto p WHERE p.descricao = :descricao")})
public class Produto implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "idproduto")
private Integer idproduto;
@Basic(optional = false)
@Column(name = "descricao")
private String descricao;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "produto")
private List vendaitemList;
public Produto() {
}
}
//imports
/**
*
* @author marciliosouza
*/
@Entity
@Table(name = "vendaitem")
@NamedQueries({
@NamedQuery(name = "Vendaitem.findAll", query = "SELECT v FROM Vendaitem v"),
@NamedQuery(name = "Vendaitem.findByIdvendaitem", query = "SELECT v FROM Vendaitem v WHERE v.idvendaitem = :idvendaitem"),
@NamedQuery(name = "Vendaitem.findByQtde", query = "SELECT v FROM Vendaitem v WHERE v.qtde = :qtde"),
@NamedQuery(name = "Vendaitem.findByPrecovenda", query = "SELECT v FROM Vendaitem v WHERE v.precovenda = :precovenda")})
public class Vendaitem implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "idvendaitem")
private Integer idvendaitem;
@Basic(optional = false)
@Column(name = "qtde")
private int qtde;
@Basic(optional = false)
@Column(name = "precovenda")
private BigDecimal precovenda;
@JoinColumn(name = "idvendaitem", referencedColumnName = "idvenda", insertable = false, updatable = false)
@OneToOne(optional = false)
private Venda venda;
@JoinColumn(name = "produto", referencedColumnName = "idproduto")
@ManyToOne(optional = false)
private Produto produto;
public Vendaitem() {
}
//gets e sets
}
//imports
import orquestralist.list.List;
/**
*
* @author marciliosouza
*/
@Entity
@Table(name = "venda")
@NamedQueries({
@NamedQuery(name = "Venda.findAll", query = "SELECT v FROM Venda v"),
@NamedQuery(name = "Venda.findByIdvenda", query = "SELECT v FROM Venda v WHERE v.idvenda = :idvenda"),
@NamedQuery(name = "Venda.findByData", query = "SELECT v FROM Venda v WHERE v.data = :data"),
@NamedQuery(name = "Venda.findByVlrtotal", query = "SELECT v FROM Venda v WHERE v.vlrtotal = :vlrtotal")})
public class Venda implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "idvenda")
private Integer idvenda;
@Basic(optional = false)
@Column(name = "data")
@Temporal(TemporalType.TIMESTAMP)
private Date data;
@Basic(optional = false)
@Column(name = "vlrtotal")
private BigDecimal vlrtotal;
@JoinColumn(name = "cliente", referencedColumnName = "idcliente")
@ManyToOne(optional = false)
private Cliente cliente;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "venda")
private List vendaitem;
public Venda() {
}
}
Agora, alguns usos Lista:
public List<Venda> example(Cliente cli)
{
return cli.getVendaList().where(new ICompare<Venda>() {
public boolean compare(Venda t) {
return t.getVlrtotal().compareTo(BigDecimal.valueOf(500)) > 0;
}
});
}
</pre>
cli.getVendaList().get(0)
.getVendaitem().where(new ICompare<Vendaitem>() { public boolean compare(Vendaitem t) {
return t.getProduto().getDescricao().equals("Produto1");
}
});
[sourcecode]
[sourcecode language="java"]
cli.getVendaList().distinct();
[sourcecode]
Obtém o total dos itens do Pedido
[sourcecode language="java"]
cli.getVendaList().get(0).getVendaitem()
.sum(new IGetValue<Vendaitem>() {
public Number getValue(Vendaitem t) {
return t.getPrecovenda().multiply(BigDecimal.valueOf(t.getQtde()));
}
});
Analisando a classe Cliente, vemos que ela tem um List<Venda>.
Na mesma classe, trocamos a declaralção do pacote para
orquestra.list, e utilizamos a classe List "with" aditivos.
Estes metodos utilitários (where por exemplo) sempre retorna uma lista
tipada mas nunca altera a lista Original.
Para o metodo where, implementamos o metodo compare e o mesmo será
executado para todos os objetos da lista, retornando uma nova lista
com os objetos que retornaram true no metodo compare().
Há outros usos, como tirar uma média como o exemplo abaixo. A interface
IGetValue<Venda> retornará o campo que será usado para o cálculo.
Outro ponto importante aqui é o uso de Generics que nos permite
especificar diretamente os campos que queremos sem precisarmos de
conversão, usar strings (que é o caso de muitos Frameworks) ou
Annotations.
Retorna a media de valores de vendas para o cliente.
public Number mediaVlrVenda(Cliente cli)
{
return cli.getVendaList().avg(new IGetValue<Venda>() {
public Number getValue(Venda t) {
return t.getVlrtotal();
}
});
}
Retorna a venda com maior valor.
public Number mediaVlrVenda(Cliente cli)
{
return cli.getVendaList().max(new Comparator<Venda>() {
public int compare(Venda o1, Venda o2) {
return o1.getVlrtotal().compareTo(o2.getVlrtotal());
}
});
}
Executa um metodo em cada objeto da Lista de itens que esta dentro da
Lista de Vendas e depois a ordena por data de emissão:
list.forEach(new Action<Venda>() {
public void action(Venda t) {
t.getVendaitem().forEach(new Action<Vendaitem>() {
public void action(Vendaitem t) {
t.setPrecovenda(BigDecimal.ZERO);
}
});
}
}).orderBy(new Comparator<Venda>() {
public int compare(Venda o1, Venda o2) {
return o1.getData().compareTo(o2.getData());
}
});
Resumindo, o que pretendo com este post, é tentar mostrar o quanto
listas podem ser extensíveis. Aqui, mostrei poucos exemplos, mas podemos
implementar diversos outros metódos dentro da List para facilitar sua
manipulação.
março 17, 2010 às 8:29 pm |
Bom, muito bom… é eu escuto vc falando disso todos os dias aqui na mesa do lado. rsrsrs
Blog ta legal.. ta começando com artigos de qualidade.
Parabén.
março 18, 2010 às 8:26 pm |
Mto bem estruturado!
Pra quem curte arroz feijão e java… prato cheio!
Não esquece de colocar Tag’s e dxa no Google!
Ainda que haja palhaço, não há show sem público !