Básico de Java para Web – parte 2
E aqui estamos com a parte 2 desse tutorial meramente conceitual de Java para a Web. Nessa parte concluirei a persistência de um modelo retornando o id gerado pelo banco no caso de uma nova instância, e implementando a atualização (update) de uma instância já persistida.
Por isso, será um post pequeno e sucinto
Ah… a primeira parte pode ser encontrada aqui.
No final da parte 1, ficou no ar o problema da obtenção do id gerado pelo banco de dados. Afinal, é necessário que a instância do model em questão tenha esse identificador para que, no caso de uma nova persistência, ele seja atualizado e não inserido novamente.
A solução é bastante simples, mas varia de banco de dados para banco de dados. Ela basicamente se resume em adicionar uma consulta pelo último id gerado pela sequência da chave primária da tabela onde ocorreu a inserção.
No caso do PostgreSQL, quando definimos um campo como “serial”, automaticamente é criada uma sequência para geração automática desse campo. O nome dessa sequência segue o padrão: tabela_campo_seq
Assim, para o PgSQL, podemos obter o último id gerado para a tabela “pessoa” através da seguinte consulta:
SELECT currval('pessoa_id_seq');
Para alguns banco de dados como MySQL e (acredito eu) SQL Server, é possível utilizar um método comum:
PreparedStatement pstmt = conn.prepareStatement(Query, Statement.RETURN_GENERATED_KEYS); pstmt.executeUpdate(); ResultSet keys = pstmt.getGeneratedKeys();Mas é necessário que o banco em questão suporte o retorno automático de chaves primárias… Infelizmente não é o caso do PostgreSQL.
Fácil, não? Agora, no BasicDao, temos que:
- construir um método para geração desse SQL;
- alterar o método “persist” para incluir este no SQL de inserção; e
- verificar o retorno da consulta para obter o id gerado.
/** * Retorna o sql para obtenção do último id inserido. * Varia de acordo com o banco de dados. * * @param model * @param conn * @return String */ private String getLastIdSQL(BasicModel model) { String sql = "; SELECT currval('"+model.getClass().getSimpleName()+"_id_seq')"; return sql; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /** * Persiste um {@link BasicModel} no banco de dados * * @param model */ public void persist(BasicModel model) { try { String persist = ""; if (model.getId() == null) { persist += getInsertSql(model); persist += getLastIdSQL(model); } else { persist += getUpdateSql(model); } Connection conn = getConnection(); PreparedStatement pstmt = conn.prepareStatement(persist); pstmt.execute(); if(model.getId() == null && pstmt.getUpdateCount() == 1 && pstmt.getMoreResults()) { ResultSet keys = pstmt.getResultSet(); if (keys.next()) { model.setId(keys.getInt(1)); } } pstmt.close(); conn.close(); } catch (Exception e) { System.err.println("Erro na operação de persistência. Operação abortada."); e.printStackTrace(); } } |
Na linha 11, a consulta pelo id é inserida. E no bloco do if da linha 22, o resultado da consulta é verificado e o id é obtido e setado no model. Temos então, o modelo persistido e com o devido id.
Agora no BasicDaoTest podemos descomentar “assertNotNull(pessoa.getId());” e rodar o teste.
Se tudo estiver ok, podemos prosseguir para a atualização de models já persistidos.
A idéia é a mesma da inserção: geraremos um SQL para atualizar os dados de uma pessoa. Agora que temos o id de uma pessoa, podemos identificá-la no banco para realizar o update. O SQL a ser gerado, será algo semelhante a:
UPDATE Pessoa SET Nome = 'Pessoa Qualquer', dataNascimento = '2009-04-07', mae = NULL, pai = NULL WHERE id = 1
Sem mais enrolação, a implementação do método ficará assim:
/** * Gera o sql para a persistência de um BasicModel já persistido * * @param model * @return * @throws java.lang.Exception */ private String getUpdateSql(BasicModel model) throws Exception { String update = "UPDATE " + model.getClass().getSimpleName(); String fields = " SET "; String where = " WHERE id = " + model.getId().toString(); boolean primeiro = true; for (Field field : model.getClass().getDeclaredFields()) { //Se o campo for uma coleção de objetos if (Collection.class.isAssignableFrom(field.getType())) { //DO NOTHING continue; } else { if (primeiro) { primeiro = false; } else { fields += ", "; } } //Se o campo for um BasicModel if (BasicModel.class.isAssignableFrom(field.getType())) { BasicModel modelField = null; try { Method method = model.getClass().getDeclaredMethod(getFieldGetterName(field.getName())); modelField = (BasicModel)method.invoke(model); if (modelField == null) { fields += field.getName() + " = null"; } else if (modelField.getId() == null) { System.err.println("O BasicModel a ser persistido possui um campo BasicModel não persistido"); throw new InvalidClassException("Class not persisted. Identifier is null."); } else { fields += field.getName() + " = " + modelField.getId().toString(); } } catch (IllegalAccessException iae) { System.err.println("Erro na leitura do campo extendido de BasicModel"); throw iae; } catch (IllegalArgumentException iae) { System.err.println("Erro na leitura do campo extendido de BasicModel"); throw iae; } } //Se for outro tipo else { Object valueField = null; fields += field.getName() + " = "; Method method = model.getClass().getDeclaredMethod(getFieldGetterName(field.getName())); valueField = method.invoke(model); if (String.class.isAssignableFrom(field.getType())) { fields += "'" + valueField.toString() + "'"; } else if(Date.class.isAssignableFrom(field.getType())) { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); fields += "'" + format.format((Date)valueField) + "'"; } else { fields += valueField.toString(); } } } update += fields + where; return update; }
Bem, como eu disse, a lógica é a mesma da construção do sql de inserção.
Agora podemos testar.
public void testPersistUpdate() throws Exception { Pessoa pessoa = new Pessoa(); pessoa.setId(1); pessoa.setDataNascimento(new Date()); pessoa.setNome("Pessoa Qualquer 2"); BasicDao basicDao = new BasicDao(); basicDao.persist(pessoa); }
Esse último teste não pode ser avaliado automaticamente sem termos um meio de obter um model persistido pelo seu id. E como não implementamos a consulta ainda, podemos apenas observar a mudança pela interface do gerenciador do banco de dados.
Então, fica para a próxima parte, implementação da consulta de um model pelo seu id e finalização da camada de persistência.

julho 27th, 2009 at 17:53
[...] também a parte 1 e a parte 2 do tutorial, caso ainda não o tenham feito.No final da parte anterior concluimos a persistência [...]