[PROMOÇÃO] Assine com + 30% de desconto ANUAL MENSAL (últimas horas)

Laravel Monitor DELETE CASCADE

[Finalizado Pelo Aluno]

Wilder Amorim
Criador Wilder Amorim 12/09/2023

Gostaria de saber qual é o motivo da decisão de não utilizar a cláusula ON DELETE CASCADE nas chaves estrangeiras. Será que isso é considerado um uso inadequado? Além disso, como é realizado o processo de exclusão em cascata a nível de código, especialmente considerando que temos diversos níveis de relacionamentos filhos? Afinal, essa funcionalidade não foi implementada.

Manager Carlos Ferreira 12/09/2023

Olá, Wilder!
Tudo bem?

Alguns motivos para não trabalhar com onDelete cascade:

1) Pode levar à perda de dados. Se um registro na tabela pai for excluído acidentalmente, todos os registros relacionados na tabela filha também serão excluídos. Isso pode levar à perda de dados importantes.

2) Pode causar problemas de desempenho. A exclusão de registros em cascata pode ser uma operação demorada, especialmente se houver muitos registros relacionados.

3) Pode ser difícil de reverter. Se você excluir um registro na tabela pai e, em seguida, perceber que cometeu um erro, pode ser difícil reverter a exclusão dos registros relacionados na tabela filha.

Carlos Ferreira
Criador Wilder Amorim 12/09/2023

Se um dado for exluído acidentalmente, sem o cascade teremos vários registros no banco pesando, isso não é outro problema?

Como é realizado o processo de exclusão em cascata a nível de código, quando temos diversos níveis de relacionamentos filhos?

Wilder Amorim
Manager Carlos Ferreira 12/09/2023

Se um dado for excluído acidentalmente, sem o cascade teremos vários registros no banco pesando, isso não é outro problema?
Problema mesmo é perder dados!!

Registros órfãos no banco apenas "ocupando espaço" não são interessantes, mas podem ser deletados a nível de código.

--

Como é realizado o processo de exclusão em cascata a nível de código, quando temos diversos níveis de relacionamentos filhos?
Obrigado a deletar primeiramente os registros filhos.

Ou delegando ainda a nível de código os registros filhos + o registro em questão.

Carlos Ferreira
Criador Wilder Amorim 12/09/2023

Tentei encontrar uma forma automática de identificar todos relacionamentos para deletar em cascada dentro do framework mas não encontrei uma solução.

Wilder Amorim
Manager Carlos Ferreira 12/09/2023

Testa pra ver se assim funciona:
public function destroy(string $id)
{
    $pai = ModelPai::with('filhos')->find($id);

    ModelFilho::destroy($pai->filhos->pluck('id'));

    $pai->delete();
}

Carlos Ferreira
Criador Wilder Amorim 12/09/2023
public function destroy(Site $site)
{
$site->endpoints()->delete();
$site->delete();

return redirect()->route('sites.index')->with('message', 'Site deletado com sucesso');
}

Neste caso, o código acima funciona se os endpoints não tiverem nenhum log.

Wilder Amorim
Manager Carlos Ferreira 12/09/2023

EndPoint::delete($site->endpoints->pluck('id'));

Carlos Ferreira
Criador Wilder Amorim 12/09/2023

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`laravel_monitor`.`checks`, CONSTRAINT `checks_endpoint_id_foreign` FOREIGN KEY (`endpoint_id`) REFERENCES `endpoints` (`id`))

Wilder Amorim
Manager Carlos Ferreira 12/09/2023

A lógica que te passei chegou a deletar os endpoints primeiro?

Carlos Ferreira
Criador Wilder Amorim 12/09/2023

Não consegue deletar os endpoints pois possuem logs relacionados a eles

Wilder Amorim
Manager Carlos Ferreira 12/09/2023

Ah sim, verdade, precisa fazer um loop:
public function destroy(Site $site)
{
    Check::delete($site->endpoints->checks->pluck('id'));
    EndPoint::delete($site->endpoints->pluck('id'));
    $site->delete();

    return redirect()->route('sites.index')->with('message', 'Site deletado com sucesso');
}

Carlos Ferreira
Criador Wilder Amorim 12/09/2023

Só consegui da seguinte maneira:

public function destroy(Site $site)
{
$site->endpoints->each(function (Endpoint $endpoint) {
Check::destroy($endpoint->checks()->pluck('id'));
$endpoint->delete();
});

$site->delete();

return redirect()->route('sites.index')->with('message', 'Site deletado com sucesso');
}

Ainda assim não me agrada, se houvesse outro relacionamento com checks, talvez teria que fazer outro loop. Existe alguma maneira automática de fazer isso, de modo que identifique os relacionamentos?

Wilder Amorim
Sérgio Danilo Rodrigues dos Santos Junior 12/09/2023

@Wilder, Credito que o mais adequado para poder executar esse delete em cascata por meio da aplicação não seja colocando esse tipo de regra no seu controller diretamente. Minimamente seria interessante criar um Job no Laravel para processar isso de maneira assíncrona. E em caso de sucesso ou erro notificar a pessoa responsável por aquele site ou endpoint em questão. Além disso colocar essas regras dentro de uma transação seria interessante. Possibilitando um controle maior do que será, de fato, commitado.

Pensa num cenário onde um determinado endpoint tenha milhares de de logs... Algo desse gênero causaria uma péssima experiência para o usuário final, ou até, ter-se-ía problema de timeout de uma requisição, por conta da demora em executar um loop, ao qual sabemos ser nada performático.

Certamente esta ação, de maneira recursiva, cabe o uso de uma fila para que a processe. Acho que cabe uma errata acerca disso no curso em questão.

Sérgio Danilo Rodrigues dos Santos Junior
Manager Carlos Ferreira 12/09/2023

Fala Sérgio!
Como vai?

Super concordo com você, seus argumentos estão corretos.

--

Vou anotar aqui para criar uma sobre deletar registros em cascata, de forma assíncrona.

Carlos Ferreira
Sabe a Solução? Ajude a resolver!

Precisa estar logado para conseguir responder a este ticket!

Clique Aqui Para Entrar!