"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Laravel SoftDelete: Evitando o problema de restrição única

Laravel SoftDelete: Evitando o problema de restrição única

Publicado em 2024-11-06
Navegar:535

Laravel SoftDelete: Avoiding the Unique Constraint Problem

Este artigo foi originado de https://medium.com/@hafiqiqmal93/laravel-softdelete-avoiding-the-unique-constraint-problem-45381d9745a0

Caso você já use o Laravel há algum tempo, especialmente quando projetos envolvem integridade de dados, provavelmente você já encontrou o recurso SoftDelete. Muito útil porque você pode “excluir” registros sem realmente retirá-los do banco de dados. O que o Laravel faz é apenas adicionar um carimbo de data e hora excluído_at para marcá-lo como excluído, mas permanece no sistema. É muito bom reter dados históricos, mas introduz um problema potencialmente complicado - o que acontece com restrições exclusivas quando você restaura registros excluídos de forma reversível?


Isso se torna um problema quando você deseja restaurar um registro que já possui, por exemplo, um email ou nome de usuário exclusivo, no banco de dados. O Laravel irá apenas gerar um erro e interromper o processo. Felizmente, existe uma maneira fácil de evitar esse problema de uma maneira muito limpa.

Vamos percorrer uma solução usando uma característica que o ajudará a contornar as restrições exclusivas ao usar SoftDelete no Laravel.

Compreendendo o problema

Vamos dar um exemplo básico. Imagine que você tem uma tabela de usuários com um campo de email que deve ser exclusivo:


Schema::create('users', function (Blueprint $table) {
    $table->string('email')->unique();
    $table->softDeletes();
});


Se você excluir um usuário com o e-mail [email protected] e depois criar um novo usuário com o mesmo e-mail, o Laravel reclamará da restrição exclusiva no campo de e-mail, gerando um erro. Na mesma situação, ao tentar restaurar o usuário excluído, o Laravel também irá reclamar da restrição exclusiva no campo email e gerar o mesmo erro.

Isso se torna uma dor de cabeça, especialmente quando se trata de grandes sistemas onde a restauração de registros é uma tarefa comum.

Para evitar isso, podemos alterar temporariamente os valores de campos exclusivos quando um registro é excluído de forma reversível e restaurar os valores originais quando o registro é recuperado. Dessa forma, o banco de dados não tropeça na restrição exclusiva durante exclusões suaves ou restaurações.

A solução: usando uma característica para evitar restrições duplicadas

Uma característica do Laravel é uma ótima maneira de encapsular essa funcionalidade. Aqui está uma característica que podemos usar para lidar com o problema:


trashed()) {
                foreach ($model->getDuplicateAvoidColumns() as $column) {
                    // handle for Spatie Translatable library
                    if (method_exists($model, 'getTranslatableAttributes')) {
                        $translates = $model->getTranslatableAttributes();
                        if (in_array($column, $translates)) {
                            foreach ($translates as $translate) {
                                if ($translate === $column) {
                                    $values = $model->getTranslations($column);
                                    foreach ($values as $translation => $value) {
                                        $values[$translation] = (explode('--', $value)[1] ?? $value);
                                    }
                                    $model->setTranslations($column, $values);
                                    break;
                                }
                            }
                            continue;
                        }
                    }
                    if ($value = (explode('--', $model->{$column})[1] ?? null)) {
                        $model->{$column} = $value;
                    }
                }
            }
        });
        static::deleted(function ($model): void {
            foreach ($model->getDuplicateAvoidColumns() as $column) {
                // handle for Spatie Translatable library
                if (method_exists($model, 'getTranslatableAttributes')) {
                    $translates = $model->getTranslatableAttributes();
                    if (in_array($column, $translates)) {
                        foreach ($translates as $translate) {
                            if ($translate === $column) {
                                $values = $model->getTranslations($column);
                                foreach ($values as $translation => $value) {
                                    $values[$translation] = time() . '--' . $value;
                                }
                                $model->setTranslations($column, $values);
                                break;
                            }
                        }
                        continue;
                    }
                }
                $model->{$column} = time() . '--' . $model->{$column};
            }
            $model->save();
        });
    }
}


Essa característica faz algumas coisas:

  • Na exclusão, ele anexa um carimbo de data/hora ao campo exclusivo, essencialmente tornando o campo único novamente sem afetar o valor original. Este truque é útil para manter restrições exclusivas satisfeitas enquanto o registro é excluído de forma reversível.
  • Na restauração, ele remove o carimbo de data/hora, restaurando o valor original do campo exclusivo.

Como funciona:

  • Manipulação de campo exclusivo: sempre que um modelo com esta característica é excluído, a característica se encarrega de anexar um carimbo de data/hora aos campos que você deseja manter exclusivos (exemplo: email, nome de usuário). Isso evita conflitos se você tentar adicionar um novo registro com os mesmos valores exclusivos.
  • Tratamento de campos traduzíveis: Se o seu modelo usa a biblioteca Spatie Translatable, essa característica é inteligente o suficiente para lidar também com campos multilíngues. Ele procura os atributos traduzíveis, ajusta seus valores e os salva com o truque do carimbo de data/hora.
  • Restauração: Quando você restaura um registro excluído de forma reversível, a característica remove o carimbo de data/hora dos campos exclusivos, retornando o campo ao seu valor original.

Aplicando a característica ao seu modelo

Veja como você pode aplicar essa característica em seu modelo Laravel:


class User extends Model
{
    use SoftDeletes, AvoidDuplicateConstraintSoftDelete;
    // Specify which columns should avoid the unique constraint issue
    public function getDuplicateAvoidColumns(): array
    {
        return ['email', 'username'];
    }
}


Ao adicionar a característica **AvoidDuplicateConstraintSoftDelete** ao seu modelo e especificar quais colunas precisam evitar conflitos de restrição exclusivos (como e-mail e nome de usuário), você pode facilmente evitar esses problemas .

Por que essa abordagem funciona?

O que isso significa é que, no caso de um registro de exclusão reversível, isso não causaria conflito com operações adicionais devido a algumas restrições exclusivas. Ou, em outras palavras, desta forma você poderá, anexando o carimbo de data/hora aos campos únicos, tornar o registro “oculto” para o banco de dados em termos de exclusividade, mas ainda recuperável quando necessário.

Isso é bastante útil quando você está lidando com um grande banco de dados e a restauração de registros é bastante comum. Você não terá que lidar sempre com o erro de “entrada duplicada” sempre que trouxer um usuário excluído de forma reversível ou qualquer outro modelo.


Considerações Finais

A coisa mais útil no Laravel é o SoftDelete, mas às vezes dá dor de cabeça ao trabalhar com restrições únicas. Aí vem uma solução simples e baseada em características que fornecerá uma maneira elegante de evitar o problema, apenas por meio de alterações temporárias de campos exclusivos na exclusão e restauração posterior. Dessa forma, você evitará erros frustrantes e permitirá que seu aplicativo funcione perfeitamente, sem quebrar restrições exclusivas em seu banco de dados.

Se algum de seus campos for multilíngue ou fizer uso de bibliotecas como Spatie’s Translatable, a solução acima funcionará sem problemas em cada um desses casos. Os SoftDeletes foram criados para oferecer flexibilidade e não atrapalhar. Com a pequena correção acima implementada, você evitará a maioria das armadilhas e manterá seus dados organizados e seus usuários satisfeitos.


Ao adicionar essa característica aos seus modelos, você economizará tempo e dores de cabeça, especialmente se estiver lidando com grandes conjuntos de dados onde a exclusão reversível e a restauração são operações frequentes. Experimente em seu projeto Laravel e você verá como ele lida facilmente com esses problemas complicados de restrições únicas!


Obrigado por ler! Não se esqueça de se inscrever para se manter informado sobre as últimas atualizações em design de sistemas e inovações em comércio eletrônico. Feliz design!

Se você achou este artigo esclarecedor e deseja se manter atualizado com mais conteúdo sobre design de sistemas e tendências tecnológicas, siga-me em :-

Twitter: https://twitter.com/hafiqdotcom
LinkedIn: https://www.linkedin.com/in/hafiq93
Compre café para mim: https://paypal.me/mhi9388 /
https://buymeacoffee.com/mhitech
Médio: https://medium.com/@hafiqiqmal93

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/afiqiqmal/laravel-softdelete-avoiding-the-unique-constraint-problem-8k2?1 Se houver alguma violação, entre em contato com [email protected] para excluí-la
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3