• Nenhum resultado encontrado

A anotação @Basic

No documento Casa do Código. Agradecimentos (páginas 96-100)

@Id

private String nomeMae;

@Id

private Date nascimento; private String nomePai; private String raca; }

Dessa forma nós continuamos tendo uma classe que representa a chave para que possamos utilizar os métodos que esperam a chave primária como o finde o getReferenceda interface EntityManager. Mas como podemos observar, os mesmos atributos que estão na classe AlunoPKestão também na classe Aluno, o que nos permite refazer a pesquisa anterior da seguinte forma:

String jpql = "select a from Aluno a " +

"where a.nascimento between :dataInicial and :dataFinal " + "and a.rendaFamiliar between :rendaMinima and :rendaMaxima"; Agora sim, podemos pesquisar atributos simples ou parte da chave da mesma forma.

5.5

A anotação @Basic

Utilizamos essa anotação para informar que uma propriedade da entidade é uma coluna no banco. No entanto, como esse já é o comportamento padrão, o uso dessa anotação é opcional e acaba ficando restrito a quando desejamos que mesmo uma propriedade comum, que não é um relacionamento, seja carregada sob demanda - ou também conhecido como Lazy Load, que vamos estudar mais na seção5.14.

@Entity

public class Automovel { private Integer id; private String descricao; ...

@Id @GeneratedValue

public Integer getId(){ return id;

Casa do Código Capítulo 5. Como mapear tudo... ou nada!

@Basic(fetch=LAZY)

public String getDescricao(){ return descricao;

} }

Com isso, a descrição só será buscada no banco de dados quando invocarmos o seu getter pela primeira vez. Porém percebemos uma diferença nesse código, que é a anotação estar no getter e não na propriedade. Precisamos disso porque o carrega- mento sob demanda de propriedades da própria entidade só funciona se anotarmos o getter. Anotando a propriedade, o carregamento será feito normalmente junto com a entidade.

5.6

@Table, @Column e @Temporal

A convenção da JPA indica que as colunas do banco terão o mesmo nome dos atri- butos das entidades, e é muito comum encontrar desenvolvedores que para deixar as classes mais limpas, sem anotações, adotam esse comportamento padrão. No en- tanto, quando mapeamos tabelas ligadas, muitas vezes o padrão de nomenclatura é diferente. Por exemplo, podemos ter nossa classe e nossa tabela da seguinte forma:

Figura 5.6: Exemplo de classe e tabela de Automovel lado a lado

Portanto, precisamos de alguma maneira fazer com que nossa entidade seja per- sistida nessa tabela. Claro que não vamos mudar os nomes dos atributos da entidade 87

5.6. @Table, @Column e @Temporal Casa do Código e acabar abrindo mão da clareza no código Java. A solução é simples, bastam alguns mapeamentos.

@Entity

@Table(name="T_AUTOMOVEIS") public class Automovel {

@Id @GeneratedValue @Column(name="COD") private Integer id;

@Column(name="DESC", nullable=false, length=100) private String descricao;

@Temporal(TemporalType.TIMESTAMP)

@Column(name="DT_CADASTRO", nullable=false, updatable=false) private Date dataCadastro;

... }

Para mapear o nome da tabela, usamos a anotação @Table, que nos permite também informar o schemado banco, caso necessário. Já para mapear a coluna, usamos a anotação @Column, que nos permite colocar vários detalhes de como essa propriedade Java vai virar uma coluna no banco.

Ao mapear a coluna podemos especificar, além do nome, se a coluna aceita valo- res nulos ou não, por meio do atributonullable, e o seu tamanho, com o length. Essas alterações refletem na estrutura da tabela, ou seja, a descrição em que indi- camos o tamanho 100 e que não é anulável será NOT NULLe possivelmente um VARCHAR(255)dependendo do banco de dados em uso.

Outra configuração interessante que fizemos é indicar se a coluna pode ter seu valor atualizado ou não. Essa última configuração não será refletida no banco de dados em si, mas sim na geração dos comandos de updateno banco. Mesmo que o usuário ou a aplicação alterem o valor da propriedade dataCadastro, quando o Automovelfor atualizado no banco, o comando updateirá ignorar essa proprie- dade.

É possível até especificar um trecho de SQL nativo do banco para gerar a coluna, para isso podemos usar a propriedade columnDefinition, mas tome cuidado, porque você poderá perder a portabilidade entre os bancos de dados:

Casa do Código Capítulo 5. Como mapear tudo... ou nada!

@Column(name="DESC", columnDefinition="CLOB NOT NULL") private String descricao;

E por fim, no nosso mapeamento temos a configuração da precisão de data que iremos utilizar. Fazemos isso usando a anotação @Temporal. Esse mapeamento pode ser usado em atributos do tipo Dateou Calendare com ele podemos espe- cificar se ao conversar com o banco de dados queremos considerar:

• DATE: somente a data, sem informação de hora; • TIME: somente informação de hora, sem data;

• TIMESTAMP: valor padrão, que considera tanto data quanto hora.

O datatype a ser utilizado pode variar de acordo com o banco de dados em uso.

5.7

@Version e lock otimista

Existem três formas de tratarmos concorrência de alteração de registros no banco de dados. A primeira, e mais usada, é não fazer nada. Nesse caso, se dois usuários leem a mesma versão de um registro, fazem alguma alteração e depois salvam, a alteração feita primeiro irá se perder, já que será sobrescrita pelo que salvar por último.

A outra opção é o que chamamos de lock pessimista. Ele tem esse nome porque parte do princípio que provavelmente irá ocorrer uma concorrência na edição do registro. Quando alguém o lê, ele já fica bloqueado somente para essa pessoa. Dessa forma, evita-se que outros usuários também editem o mesmo registro.

Muitas vezes quando carregamos as informações para o usuário, ele tem na mesma tela a opção de visualizar ou editar. A simples visualização não causa pro- blema de concorrência, mas como estamos sendo pessimistas, acabamos conside- rando que quando esse registro for lido provavelmente ele será alterado, então esse bloqueio é feito para escrita. O problema é que quando outro usuário for visuali- zar o mesmo registro, por estar usando a mesma tela que o primeiro, vamos querer um bloqueio de escrita para ele também. Mas como o registro já está bloqueado, o segundo usuário não consegue nem ler.

Isso fica pior ainda se o banco de dados utilizado não suportar bloqueio de linha. Nesse caso, por mais que solicitemos o bloqueio de uma única linha, a tabela inteira fica bloqueada, causando um problema enorme na aplicação. Em um sistema razo- avelmente utilizado, em poucos minutos teríamos “engarrafamentos quilométricos” no nosso banco de dados.

5.8. Relacionamentos muitos para um com @ManyToOne Casa do Código

No documento Casa do Código. Agradecimentos (páginas 96-100)