Pergunta

Ainda estou aprendendo o Hibernate/HQL e tenho uma pergunta que é metade das melhores práticas/meia sanidade.

Digamos que eu tenho uma classe A:

@Entity
public class A
{
    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    @Column(unique=true)
    private String name = "";

    //getters, setters, etc. omitted for brevity
}

Quero aplicar que todas as instâncias de A que são salvas têm um nome único (daí a anotação @Column), mas também quero poder lidar com o caso em que já há uma instância A salva que tem esse nome. Eu vejo duas maneiras de fazer isso:

1) Eu posso capturar o org.hibernate.exception.ConstraintviolationException que pode ser jogado durante a sessão.SaveorUpdate () Ligue e tente lidar com isso.

2) Posso consultar as instâncias existentes de A que já possui esse nome no DAO antes de ligar session.SaveorUpdate ().

No momento, estou inclinado para a abordagem 2, porque na abordagem 1 não sei como descobrir programaticamente qual restrição foi violada (existem alguns outros membros únicos em a). No momento, meu código dao.save () se parece mais com o seguinte:

public void save(A a) throws DataAccessException, NonUniqueNameException
{
    Session session = sessionFactory.getCurrentSession();

    try
    {
        session.beginTransaction();

        Query query = null;

        //if id isn't null, make sure we don't count this object as a duplicate
        if(obj.getId() == null)
        {
            query = session.createQuery("select count(a) from A a where a.name = :name").setParameter("name", obj.getName());
        }
        else
        {
            query = session.createQuery("select count(a) from A a where a.name = :name " + 
                "and a.id != :id").setParameter("name", obj.getName()).setParameter("name", obj.getName());
        }

        Long numNameDuplicates = (Long)query.uniqueResult();
        if(numNameDuplicates > 0)
            throw new NonUniqueNameException();

        session.saveOrUpdate(a);
        session.getTransaction().commit();
    }
    catch(RuntimeException e)
    {
            session.getTransaction().rollback();
            throw new DataAccessException(e); //my own class
    }
}

Estou fazendo isso da maneira certa? O Hibernate pode me dizer programaticamente (ou seja, não como uma string de erro) qual valor está violando a restrição de singularidade? Ao separar a consulta da confirmação, estou convidando erros de segurança de linhas ou estou seguro? Como isso geralmente é feito?

Obrigado!

Foi útil?

Solução

Eu acho que sua segunda abordagem é melhor.

Para poder capturar a exceção da restrição de vínculo com qualquer certeza de que esse objeto em particular o causasse, você precisaria liberar a sessão imediatamente após a chamada para salvar o SavorUpdate. Isso pode introduzir problemas de desempenho se você precisar inserir vários desses objetos por vez.

Mesmo que você testasse se o nome já existir na tabela em todas as ações salvas, isso ainda seria mais rápido do que nivelado após cada inserção. (Você sempre pode comparar para confirmar.)

Isso também permite estruturar seu código de forma que você possa chamar de 'validador' de uma camada diferente. Por exemplo, se essa propriedade exclusiva for o email de um novo usuário, na interface da Web, você poderá chamar o método de validação para determinar se o endereço de email é aceitável. Se você adotasse a primeira opção, saberia apenas se o email era aceitável depois de tentar inseri -lo.

Outras dicas

A abordagem 1 ficaria bem se:

  • Existe apenas uma restrição na entidade.
  • Existe apenas um objeto sujo na sessão.

Lembre -se de que o objeto não pode ser salvo até flush() é chamado ou a transação comprometida.

Para melhor relatar erros, eu faria:

  1. Use a abordagem dois para cada violação de restrição, para que eu possa dar um erro específico para cada um deles.
  2. Implemente um interceptador que, em caso de uma exceção de restrição, experimenta a transação (um número máximo de vezes) para que a violação não possa ser capturada em um dos testes. Isso só é necessário, dependendo do nível de isolamento da transação.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top