Pergunta

Qual é a melhor prática para lidar com exceções em NHibernate?

Eu tenho um SubjectRepository com o seguinte:

    public void Add(Subject subject)
    {
        using (ISession session = HibernateUtil.CurrentSession)
        using (ITransaction transaction = session.BeginTransaction())
        {

            session.Save(subject);
            transaction.Commit();
        }
    }

E uma unidade de teste da seguinte forma:

        [Test]
    public void TestSaveDuplicate()
    {
        var subject = new Subject
        {
            Code = "En",
            Name = "English"
        };

        _subjectRepository.Add(subject);

        var duplicateSubject = new Subject
        {
            Code = "En",
            Name = "English1"
        };

        _subjectRepository.Add(duplicateSubject);
    }

Eu cheguei ao ponto de lidar com o erro gerado pelo teste de unidade e tem um pouco preso. Esta falha como esperado, embora com uma GenericADOException, eu estava esperando um ConstraintViolationException ou algo semelhante (há uma restrição de exclusividade sobre o código do tema a nível de banco de dados).

O ADOException envolve uma exceção de MySQL que tem uma mensagem de erro sensata, mas eu não quero começar encapsulamento quebra por apenas jogando a exceção interna. Particularmente como MySQL não está finalizado como o back-end para este projeto.

Idealmente, eu gostaria de ser capaz de capturar a exceção e retornar um erro sensata para o usuário neste momento. Há algum melhores práticas documentadas abordagens para tratamento de exceções NHibernate e relatórios de volta para o usuário que deu errado e por quê?

Obrigado,

Matt

Foi útil?

Solução

Gostaria de lidar com isso no método Add como tal:

public void Add(Subject subject)
{
    using (ISession session = HibernateUtil.CurrentSession)
    using (ITransaction transaction = session.BeginTransaction())
    {
        try
        {
            session.Save(subject);
            transaction.Commit();
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            // log exception
            throw;
        }
    }
}

No bloco catch, você deve primeiro reverter a transação e log a exceção. Em seguida, as opções são:

  1. relançar a mesma exceção, que é o que a minha versão faz
  2. envolvê-la em sua própria exceção e jogar esse
  3. Swallow exceção por não fazer nada, o que é muito raramente uma boa idéia

Você não tem quaisquer opções reais para lidar com a exceção neste método. Assumindo que a interface do usuário chama esse método, deve chamá-lo em seu próprio try..catch e manipulá-lo, exibindo uma mensagem de erro significativo para o usuário. Você pode fazer o seu cartão de teste de unidade usando o atributo ExpectedException (tipo).

Para responder à sua pergunta diretamente, você deve criar o seu próprio "erro sensível" ao estender Exception e jogar que, com a exceção original como seu InnerException. Essa é a técnica de exceção embrulho I listados em (2).

Outras dicas

exceções

Todos os NHibernate não são recuperáveis, você poderia rever o projeto da camada de aplicativo / dados se você está tentando se recuperar de exceções nhibernate. Você também pode dar uma olhada spring.net 's tradução exceção implementaion Também você lidar manualmente transações on exceções é tedioso e propenso a erros, dar uma olhada em sessões contextuais do nhibernate . Spring.net também tem alguns ajudantes agradáveis ??em torno nhibernate.

A questão geral vai ser, o que você quer dizer ao usuário, e quem é o usuário?

Se o usuário, por vezes, será outro computador (ou seja, este é um serviço web), então você iria querer usar o mecanismo apropriado para retornar uma falha SOAP ou HTTP erro.

Se o usuário, por vezes, será um UI de algum tipo, então você pode querer exibir uma mensagem para o usuário, mas o que você dizer ao usuário para que ele possa fazer algo sobre isso? Por exemplo, a maioria dos sites vai dizer: "Desculpe, ocorreu um erro inesperado", não importa o que a razão. Isso porque geralmente há nada que o usuário poderia fazer sobre o erro.

Mas em qualquer caso, a escolha de como dizer "o usuário" é uma questão para a camada de apresentação (UI nível), não para o DAL. Você deve, possivelmente, envolver exceções do DAL em outro tipo de exceção, mas apenas se você estiver indo para mudar a mensagem. Você não precisa de sua própria classe de exceção, a menos que o seu interlocutor faria algo diferente se é uma exceção de acesso de dados ao invés de algum outro tipo.

Eu provavelmente validar a entrada antes de salvar o objeto; de que maneira você pode implementar qualquer que seja a validação você gosta (por exemplo, verificar o comprimento do Sujeito Código, bem como o fato de que não existem quaisquer duplicatas), e passar para trás os erros de validação significativas para o usuário.

A lógica é a seguinte; exceções são usados ??para indicar as circunstâncias excepcionais que o seu programa não servem para. Um usuário digitando um código Assunto duplicado no seu exemplo acima é algo que seu programa deve ser suficiente para; por isso, em vez de lidar com uma exceção porque uma restrição DB fica violado (que é um evento excepcional e não deve estar ocorrendo), você iria querer lidar com esse cenário primeira e única tentativa de salvar os dados quando você sabe que os dados 'poupança re está correto.

A vantagem com a implementação de todas as regras de validação em seu DAL é que você pode, em seguida, garantir que os dados entrando em seu DB é válido de acordo com seus processos de negócios de uma forma consistente, em vez de depender dos constrangimentos na sua DB para pegar aqueles para você.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top