AUTOINCREMENTO SEM PERDER SEQUENCIA
Bem pessoal achei esse outro código, como disse na resposta anterior, que faz uso de uma tabela auxiliar só para os IDs das tabelas que serão controladas.
O que gostaria de saber é como fazer o código de uma forma genérica, onde eu pudesse informar múltiplas tabelas como origem. Será que terei de ter um Trigger especÃfico para cada tabela? Ou poderia usar o nome da tabela como algum parâmetro passado pelo C#?
[/b]Pergunta: Como funcionaria isso?[/b]
-- Cria a tabela de pessoas
CREATE TABLE tblPessoas (IDPessoa INT NOT NULL, NomePessoa VARCHAR(50))
ALTER TABLE tblPessoas ADD CONSTRAINT PKPessoa PRIMARY KEY (IDPessoa)
-- Cria a tabela de contadores (IDs)
CREATE TABLE tblContadores (NomeTabela VARCHAR(20), Valor INT)
INSERT INTO tblContadores VALUES ([ô]tblPessoas[ô],0)
-- Cria a trigger de inserção
CREATE TRIGGER tblSeqPessoa ON tblPessoas
INSTEAD OF INSERT
AS BEGIN
-- Captura o ID atual (bloqueando-o para que duas pessoas não peguem o mesmo ID)
DECLARE @IDPessoa INT
SET @IDPessoa = (SELECT VALOR FROM tblContadores (XLOCK) WHERE NomeTabela = [ô]tblPessoas[ô])
SET @IDPessoa = @IDPessoa + 1
-- Atualiza o contador
UPDATE tblContadores SET Valor = Valor + 1 WHERE NomeTabela = [ô]tblPessoas[ô]
-- Insere o registro
INSERT INTO tblPessoas (IDPessoa, NomePessoa)
SELECT @IDPessoa AS IDPessoa, NomePessoa FROM INSERTED
END
-- Simula uma inserção
INSERT INTO tblPessoas (NomePessoa) VALUES ([ô]Nome 1[ô])
-- Verifica o registro
SELECT IDPessoa, NomePessoa FROM tblPessoas
-- Verifica o contador
SELECT NomeTabela, Valor FROM tblContadores
O que gostaria de saber é como fazer o código de uma forma genérica, onde eu pudesse informar múltiplas tabelas como origem. Será que terei de ter um Trigger especÃfico para cada tabela? Ou poderia usar o nome da tabela como algum parâmetro passado pelo C#?
[/b]Pergunta: Como funcionaria isso?[/b]
INSERT INTO CLIENTE (id,nome)--- SEM IDENTITY OU AUTO INCREMENTO
VALUES
(SELECT isnull(max(id),0)+1,[ô]FULANO[ô]) -- SE ESTIVER NULL ELE ACRECENTA ASSIM MESMO LEMBRANDO QUE ESSA PARTE [Ô]SELECT isnull(max(id),0)+1[Ô] REPRESENTA O ACRECIMO DO ID
FROM CLIENTE
VALUES
(SELECT isnull(max(id),0)+1,[ô]FULANO[ô]) -- SE ESTIVER NULL ELE ACRECENTA ASSIM MESMO LEMBRANDO QUE ESSA PARTE [Ô]SELECT isnull(max(id),0)+1[Ô] REPRESENTA O ACRECIMO DO ID
FROM CLIENTE
O grande problema é a questão da duplicidade. Evitando a auto-numeração, vc tem duas opções: trata o erro quando houver duplicidade ou trava a tabela no processo da criação desse identificador tendo que ter um tratamento para os processos que se depararem com a tabela travada.
Já trabalhei com um sistema que tinha uma tabela controladora de IDs para várias outras e era um inferno a duplicidade se não fosse tratado com travas.
Já trabalhei com um sistema que tinha uma tabela controladora de IDs para várias outras e era um inferno a duplicidade se não fosse tratado com travas.
pode usar tratamento de erro
EX: sqlserver
BEGIN TRY
-- o codigo a ser feito
END TRY
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_MESSAGE() as RETORNO
END CATCH
EX: sqlserver
BEGIN TRY
-- o codigo a ser feito
END TRY
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_MESSAGE() as RETORNO
END CATCH
Então LAIA no código que postei acima, dizia no forum que trava a tabela de origem dos IDs acho que é nessa linha:
Mas assim qualquer inserção em tabelas que se utilizem desse recurso seriam tratavas pelo que entendi, e teria de ter um tratamente em cada uma delas.
No VB6 com Access, eu pegava o Max(ID) + 1 e gravava, se desse erro, eu interceptava, checava o código para ver se era de já ter o ID gravado, e mandava reiniciar com Goto na linha que pegava o Max(ID) + 1 novamente., até que conseguisse gravar. Nesse aplicativo nunca tive problema.
Agora quero fazer o mesmo aqui no C# + SQL Server. Como é um gerenciador de bancos, pensei que fosse mais simples e não precisaria tratar no código, mas pelo que estou vendo, vai ser muito mais fácil e [Ô]Seguro[Ô] tratar no código com Max() + 1 do que fazer esse monte de coisas no banco que depois nem terei acesso, só via código e por aplicativos feitos para essa manutenção que dará mais trabalho, já no código basta recompilar e distribuir.
Acho que esse código do Fellipe vai facilitar tudo, pois não faço nada no banco:
Tenho só duas dúvidas:
1- usando o insert acima, como eu obtenho o ID gravado para poder atribuir aos campos das tabelas relacionadas?
No inserte com autoincremento, faço assim:
2- Qual é o código de tratamento de erro que é gerado pelo SqlException para este caso do ID já existir?
SET @IDPessoa = (SELECT VALOR FROM tblContadores (XLOCK) WHERE NomeTabela = [ô]tblPessoas[ô])
Mas assim qualquer inserção em tabelas que se utilizem desse recurso seriam tratavas pelo que entendi, e teria de ter um tratamente em cada uma delas.
No VB6 com Access, eu pegava o Max(ID) + 1 e gravava, se desse erro, eu interceptava, checava o código para ver se era de já ter o ID gravado, e mandava reiniciar com Goto na linha que pegava o Max(ID) + 1 novamente., até que conseguisse gravar. Nesse aplicativo nunca tive problema.
Agora quero fazer o mesmo aqui no C# + SQL Server. Como é um gerenciador de bancos, pensei que fosse mais simples e não precisaria tratar no código, mas pelo que estou vendo, vai ser muito mais fácil e [Ô]Seguro[Ô] tratar no código com Max() + 1 do que fazer esse monte de coisas no banco que depois nem terei acesso, só via código e por aplicativos feitos para essa manutenção que dará mais trabalho, já no código basta recompilar e distribuir.
Acho que esse código do Fellipe vai facilitar tudo, pois não faço nada no banco:
INSERT INTO CLIENTE (id,nome)
VALUES (SELECT isnull(max(id),0)+1,[ô]FULANO[ô])
FROM CLIENTE
Tenho só duas dúvidas:
1- usando o insert acima, como eu obtenho o ID gravado para poder atribuir aos campos das tabelas relacionadas?
No inserte com autoincremento, faço assim:
Int32 novaAtitudeID = 0;
string sql = [Ô]INSERT INTO ATITUDES (ATITUDE,IDIOMA,INATIVO) VALUES (@DESCRICAO,@IDIOMA,@INATIVO); [Ô]
+ [Ô]SELECT CAST(scope_identity() AS int)[Ô];
SqlCommand cmd = new SqlCommand(sql, Dados.cn);
...
novaAtitudeID = (Int32)cmd.ExecuteScalar();
2- Qual é o código de tratamento de erro que é gerado pelo SqlException para este caso do ID já existir?
desculpa a demora hehe.Bom vc poderia fazer assim.
é uma procedure
BEGIN TRY
DECLARE @cod_novo INT
BEGIN TRAN
--Inserir na Tabela exemplo tabela1
INSERT INTO tabela1 (codigo,nome,data_cad)
VALUES (@codigo,@nome,getdate())
SELECT @cod_novo = codigo
-- inserir tabela tabela2
INSERT INTO tabela2(codigo,telefone,email)
VALUES (@cod_novo,@telefone,@email)
SELECT @cod_novo AS RETORNO --retorno é só o nome da coluna para não ficar em branco
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_MESSAGE() AS RETORNO --RETORNO SERà O CAMPO ONDE A EXCEÇAO IRà EXIBIR
END CATCH
é usado o mesmo codigo em duas tabelas e depois retorna o codigo inserido, ai fica ao seu critério
é uma procedure
BEGIN TRY
DECLARE @cod_novo INT
BEGIN TRAN
--Inserir na Tabela exemplo tabela1
INSERT INTO tabela1 (codigo,nome,data_cad)
VALUES (@codigo,@nome,getdate())
SELECT @cod_novo = codigo
-- inserir tabela tabela2
INSERT INTO tabela2(codigo,telefone,email)
VALUES (@cod_novo,@telefone,@email)
SELECT @cod_novo AS RETORNO --retorno é só o nome da coluna para não ficar em branco
COMMIT TRAN
END TRY
BEGIN CATCH
ROLLBACK TRAN
SELECT ERROR_MESSAGE() AS RETORNO --RETORNO SERà O CAMPO ONDE A EXCEÇAO IRà EXIBIR
END CATCH
é usado o mesmo codigo em duas tabelas e depois retorna o codigo inserido, ai fica ao seu critério
Tópico encerrado , respostas não são mais permitidas