Eu tenho uma tabela no Microsoft SQL Server. Às vezes preciso atualizar e às vezes preciso inserir. Eu poderia escrever 2 procedimentos armazenados:
InsertNewPerson
UpdatePertsonById
Mas eu estava pensando em escrever 1 procedimento armazenado ( SetPerson
) que faria as duas coisas (se houver um ID
, é uma update
operação , caso contrário insert
).
Devo criar um procedimento armazenado (apenas um para manter) ou devo criar dois procedimentos armazenados diferentes?
Pelo que entendi, você não está realmente falando sobre um
UPSERT
aqui apenas combinando duas operações CRUD diferentes em um procedimento armazenado.O benefício que vejo nisso é que você não precisa manter duas listas de parâmetros separadas se a estrutura da tabela for alterada. A desvantagem é que o único procedimento armazenado agora tem duas responsabilidades e é um pouco menos fácil de entender.
Eu geralmente optaria por separá-los em dois procedimentos armazenados.
RE: "Você pode elaborar como um upsert ficará"
Isso pressupõe que
Id
não é mais umaIDENTITY
coluna. A razão para usarHOLDLOCK
é explicada aqui .Se você quiser usar um procedimento, pode usar a instrução MERGE .
Exemplo de código de mesclagem:
A maior desvantagem é que o desempenho será pior (embora você possa atenuar os problemas de desempenho por meio de uma indexação criteriosa ). Contrariando isso, existem algumas vantagens.
A primeira vantagem é que a auditoria é muito mais completa , pois você tem acesso aos valores dos registros SOURCE e TARGET caso precise. Isso é algo que você não pode obter das cláusulas OUTPUT de INSERT ou UPDATE.
A segunda vantagem dessa abordagem é que você pode criar um parâmetro com valor de tabela em sua camada de dados em vez de usar parâmetros individuais (como fiz neste exemplo rápido) e usá-lo como a tabela SOURCE. Isso significa que você poderia teoricamente inserir/atualizar vários registros na mesma chamada. Concedido, você poderia fazer o mesmo com instruções INSERT e UPDATE separadas no mesmo procedimento ou dois procedimentos armazenados separados, mas isso permite manter uma instrução T-SQL em vez de duas.
Por fim, se você quiser fazer o esforço necessário, poderá pegar os resultados da cláusula OUTPUT do Merge (@results no exemplo acima), alimentá-los de volta para .NET (ou qualquer que seja sua camada de aplicativo) e atualizar seus objetos com os resultados da tabela. Não é um exercício trivial, mas economiza outra chamada Get. E se você inserir vários registros simultaneamente, não precisa se preocupar em tentar obter os resultados da coluna de identidade via SCOPE_IDENTITY(): a pseudotabela inserida já possui o valor da coluna de identidade para cada registro.
Novamente, a maioria das vantagens são coisas que você pode replicar com instruções de inserção e atualização separadas, portanto, isso se resume principalmente ao custo de desempenho do MERGE versus o benefício de manutenção de ter que acertar em um local em vez de dois, e não precisar separar insira/atualize a lógica em suas camadas de negócios ou dados.