Por que `SELECT @@ IDENTITY` está retornando um decimal?

24

Estou usando o Dapper para executar a seguinte consulta em uma instância do SQL Server 2008 R2 Express de um aplicativo ASP.NET MVC 3 (.NET 4.0).

INSERT INTO Customers (
         Type, Name, Address, ContactName, 
         ContactNumber, ContactEmail, Supplier)
VALUES (
         @Type, @Name, @Address, @ContactName, 
         @ContactNumber, @ContactEmail, @Supplier)

SELECT @@IDENTITY

A chamada para connection.Query<int>(sql, ...)está lançando uma exceção de conversão inválida. Eu depurei e é no ponto em que Dapper chama GetValueo retornado SqlDataReader.

O tipo de retorno GetValueé Object: inspecionando-o no programa de depuração, é um decimal em caixa.

Se eu alterar o select para SELECT CAST(@@IDENTITY as int), o retorno de GetValue será um int em caixa e a exceção não será lançada.

A coluna Id é definitivamente do tipo int; Por que SELECT @@IDENTITYretornaria um decimal?

Algumas informações adicionais:

  • O banco de dados é novo em folha.
  • A tabela Customers é o único objeto que eu adicionei a ela. Não há outras tabelas (usuários), visualizações, gatilhos ou procedimentos armazenados no banco de dados.
  • Existem 10 linhas no banco de dados, existem IDs 1,2,3,4,5,6,7,8,9,10 (ou seja, a coluna não está além dos limites de um int).

Minha definição de tabela é

CREATE TABLE [dbo].[Customers](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Type] [int] NOT NULL,
    [Name] [nvarchar](255) NOT NULL,
    [Address] [nvarchar](1000) NOT NULL,
    [ContactName] [nvarchar](255) NOT NULL,
    [ContactNumber] [nvarchar](50) NOT NULL,
    [ContactEmail] [nvarchar](255) NOT NULL,
    [Supplier] [nvarchar](255) NOT NULL,
 CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (
    PAD_INDEX  = OFF, 
    STATISTICS_NORECOMPUTE  = OFF, 
    IGNORE_DUP_KEY = OFF, 
    ALLOW_ROW_LOCKS  = ON, 
    ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
Greg B
fonte
Você tem algum gatilho na tabela Customers?
Richard
3
Eu usaria SCOPE_IDENTITY () em vez de @@ IDENTITY. @@ IDENTITY fornecerá o último valor de identidade criado por qualquer coisa na conexão atual, em oposição ao seu escopo atual. Portanto, como Richard sugeriu, um gatilho modificando outra tabela e gerando uma identidade afetaria o retorno de @@ IDENTITY.
quer
Não há gatilhos no banco de dados. É um banco de dados novo e a tabela Customers é a única tabela que eu criei.
Greg B.
@ Greg B: este é o tipo de retorno da função. Você esperava int / bigint como o tipo de retorno (como a pergunta sugere) ou está questionando a escolha do MS para esta função?
Marian

Respostas:

28
  1. @@ identity retorna um numérico (38,0) . Você precisará convertê-lo para obter um int.

    SELECIONAR CAST (@@ identidade AS INT)

  2. Além disso, tente usar scope_identity. Se houver algum gatilho na tabela Customers, você poderá obter a última identidade de outra tabela.

  3. Por fim, como você está usando o dapper , deseje agrupar tudo isso em um procedimento armazenado para garantir a execução da inserção e a seleção na identidade no mesmo lote.

    Teoricamente, deve funcionar a maior parte do tempo para executar os dois por conta própria. Mas podem surgir problemas se você precisar acessar o banco de dados duas vezes. (Por exemplo, como isso funciona com o pool de conexões? E quanto às conexões perdidas? Etc.) Se você simplesmente jogar tudo em um procedimento armazenado, não precisará se preocupar com esse esforço extra no futuro.

Richard
fonte
Obrigado por # 3. Não há como definir um lote em uma instrução SQL adhoc ?
Greg B.
Eu estava dando outra olhada nisso. Se você incluir todas as instruções em uma chamada, será tudo um lote. Se você dividir as declarações em chamadas separadas, as coisas podem ficar ruins.
Richard
3
+1 por recomendar SCOPE_IDENTITY ()
Andrew Bickerton
10

Criar tabela diz:

" IDENTIDADE

Indica que a nova coluna é uma coluna de identidade. Quando uma nova linha é adicionada à tabela, o Microsoft® SQL Server ™ fornece um valor incremental exclusivo para a coluna. As colunas de identidade são comumente usadas em conjunto com as restrições PRIMARY KEY para servir como o identificador de linha exclusivo da tabela. A propriedade IDENTITY pode ser atribuída às colunas tinyint, smallint, int, bigint, decimal (p, 0) ou numérico (p, 0). Somente uma coluna de identidade pode ser criada por tabela. Padrões limitados e restrições DEFAULT não podem ser usados ​​com uma coluna de identidade. Você deve especificar a semente e o incremento ou nenhum. Se nenhum for especificado, o padrão é (1,1).

semente

É o valor usado para a primeira linha carregada na tabela.

incremento

O valor incremental adicionado ao valor de identidade da linha anterior foi carregado. "

Portanto, a função do sistema @@ identity terá que lidar com o tipo de cobertura mais alto.

Marian
fonte
E é por isso que ele retorna numericcomo tem a maior variedade ..? Obrigado
Greg B
3
Uma função não pode ter mais de um tipo de retorno. Ele precisará usar o tipo mais amplo para incluir todas as possibilidades.
Marian
6

"Por que SELECT @@ IDENTITY retornaria um decimal"

Como pode ser muito grande para caber em um int- ele não corresponde ao tipo da coluna de identidade, mas, como Richard diz, retorna um numérico (38,0) ( numerice decimal é sinônimo )

Jack Douglas
fonte