Pergunta

Eu sempre senti que as exceções que esperam para ser jogado em uma base regular e usá-los como lógica de fluxo era uma coisa ruim. Exceções sentir como eles devem ser, assim, o " exceção ". Se você está esperando e planejamento para uma exceção, que parece indicar que o código deve ser reformulado, pelo menos em .NET ...
Contudo. Um cenário recente me deu pausa. Eu postei isso no MSDN há um tempo atrás, mas eu gostaria de gerar mais discussão sobre isso e este é o lugar perfeito!

Então, digamos que você tem uma tabela de banco de dados que tem uma chave estrangeira para várias outras mesas (no caso que originalmente levou o debate, houve 4 chaves estrangeiras apontando para ele). Você deseja permitir que o usuário exclua, mas somente se não há referências de chave estrangeira; você NÃO quer em cascata delete.
Eu normalmente apenas fazer uma verificação para ver se há quaisquer referências, e se houver, eu informar o usuário em vez de fazer a exclusão. É muito fácil e relaxante para escrever isso em LINQ como tabelas relacionadas são membros sobre o objeto, de modo Section.Projects e Section.Categories e et cetera é bom para digitar com intellisense e tudo ...
Mas o fato é que LINQ, então tem que bater potencialmente todos os 4 mesas para ver se existem linhas de resultados que apontam para esse registro, e bater o banco de dados é obviamente sempre uma operação relativamente caro.

O lidera este projecto me pediu para alterá-lo para apenas pegar um SqlException com um código de 547 (restrição de chave estrangeira) e lidar com ele dessa forma.

Eu estava ...
resistente .

Mas, neste caso, é provavelmente muito mais eficiente para engolir a sobrecarga exceção relacionada com a engolir os 4 hits de mesa ... Especialmente desde que nós temos que fazer a verificação em todos os casos, mas estamos poupados exceção no caso quando não há crianças ...
Além disso, o banco de dados realmente deve ser o único responsável por tratar a integridade referencial, que é o seu trabalho e ele faz isso bem ...
Então eles ganharam e eu mudei.

Em algum nível ele ainda se sente errado para me embora.

O que vocês pensam sobre esperando e tratamento de exceções intencionalmente? Está tudo bem quando parece que vai ser mais eficiente do que a verificação de antemão? É mais confuso para a próxima desenvolvedor olhando para o seu código, ou menos confuso? É mais seguro, uma vez que o banco de dados pode saber sobre as novas restrições de chave estrangeira que o desenvolvedor não pode pensar para adicionar um cheque de? Ou é uma questão de perspectiva sobre o que exatamente você acha melhor prática é?

Foi útil?

Solução

Uau,

Primeiro, você pode por favor destilar a questão um pouco para baixo, enquanto ele era agradável para ler um bem pensado e explicou questão, que foi muito para digerir.

A resposta curta é "sim", mas pode depender.

  • Nós temos algumas aplicações onde temos muita lógica de negócios amarrado nas consultas SQL (não meu projeto Gov!). Se esta é a forma como ele está estruturado, a gestão pode ser difícil convencer de outra forma, uma vez que "já trabalha".
  • Nesta situação, isso realmente fazer um grande negócio? Como ainda é uma viagem através do fio e para trás. Será que o servidor fazer muito antes que ele percebe que não pode continuar (i.e.if há uma seqüência de transações que ocorrem à sua acção, não é, em seguida, cair a meio, perdendo tempo?).
  • Será que faz sentido para fazer o check-in a interface do usuário em primeiro lugar? Isso ajuda com a sua aplicação? Se ele fornece uma experiência melhor do usuário? (Ou seja, eu tenho visto casos onde você caminha por várias etapas em um assistente, ele começa, então cai, quando dispunha de todas as informações de que precisava para cair depois do passo 1).
  • é a simultaneidade um problema? É possível que o registro possa ser removido / editado ou o que quer antes de seu cometer ocorre (como no File.Exists dodói clássico).

Na minha opinião:

eu faria ambos . Se eu posso falhar rapidamente e proporcionar uma experiência de usuário melhor, ótimo. Qualquer SQL esperado (ou qualquer outro) excepções devem ser pego e alimentado de volta adequadamente de qualquer maneira.

Eu sei que há um consenso de que as exceções não devem ser utilizados para outros fins que circunstâncias excepcionais , mas lembre-se, estamos cruzando os limites do aplicativo aqui, esperar nada . Como eu disse, este é como o File.Exists, não há nenhum ponto, ele pode ser excluído antes de acessá-lo de qualquer maneira.

Outras dicas

A sua liderança é absolutamente certo. As exceções são não apenas por uma vez em um azul situações lua, mas especificamente para relatar que não os resultados esperados.

Neste caso, a verificação de chave estrangeira ainda ter lugar, e exceções são o mecanismo pelo qual você pode ser notificado.

O que você não deve fazer é interceptar e eliminar exceções com uma declaração cobertor catchall. Fazer tratamento de exceção de grão fino é especificamente porque exceções foram projetados em primeiro lugar.

Eu acho que você está certo, exceções só deve ser usado para lidar com inesperado resultados, aqui você estiver usando uma exceção para lidar com um resultado possivelmente esperado, você deve lidar com este caso de forma explícita, mas ainda captura a exceção para mostrar um possível erro.

A menos que esta é a forma como este caso é tratado por todo o código, eu ficaria do lado com você. O problema de desempenho só deve ser levantada se é realmente um problema, ou seja, que depende do tamanho dessas tabelas eo número de vezes que esta função é utilizada.

questão Nice. No entanto, eu encontrar as respostas ... assustador!
Uma exceção é uma espécie de GOTO.
Eu não gosto de usar exceções desta forma porque que leva ao código espaguete.
Simples assim.

Não há nada de errado com o que você está fazendo. Exceções não são nessesarily "excepcional". Eles existem para permitir chamar objetos ter grão fino manipulação de erro dependendo de suas necessidades.

Travando a SqlException específica é a coisa certa a fazer. Este é o mecanismo pelo qual o SQL Server comunica a condição de chave estrangeira. Mesmo que você pode favorecer um uso diferente do mecanismo de exceção, isto é como SQL Server faz isso.

Além disso, durante o seu controlo sobre as quatro mesas, algum outro usuário pode adicionar um registro relacionado antes de sua verificação é concluída, mas depois de ler essa tabela.

Eu recomendo chamar um procedimento armazenado que verifica se existem quaisquer dependências, em seguida, exclui se não houver qualquer. Dessa forma, a verificação de integridade é feito.

Claro, você provavelmente quer um procedimento armazenado diferente para Singleton exclusões vs. exclusão em lote ... O lote excluir poderia procurar linhas filho e retornar um conjunto de registros que não eram elegíveis para um volume de exclusão (tinha linhas filho).

Eu não gosto de ver as exceções em todos os lugares em um programa, mas neste caso eu usaria o mecanismo de exceção.

Mesmo se você testar em LINQ, você terá que capturar a exceção no caso de alguém insere um registro filho enquanto você está integridade testes com LINQ. Desde que você tem que verificar a exceção de qualquer maneira, por que duplicar o código?

Outro ponto é que este tipo de exceção "curto alcance" não causa problemas de manutenção, nem faz o seu programa mais difícil de ler. Você terá a chance, a chamada SQL para excluir, e as capturas, tudo o que dentro de 10 linhas de código, juntos. A intenção é óbvia.

Não como jogar uma exceção que deve ser catched 5 chamadas de procedimento superior na pilha, com os problemas de ter a certeza que todos os objetos entre ter cuidado sido (libertou) corretamente.

As excepções nem sempre são uma resposta mágica, mas eu não me sentiria errado usá-los nesta situação.

Os meus dois centavos,

Yves

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