Perché `SELECT @@ IDENTITY` restituisce un decimale?


24

Sto usando Dapper per eseguire la seguente query su un'istanza di SQL Server 2008 R2 Express da un'applicazione 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

La chiamata a connection.Query<int>(sql, ...)sta generando un'eccezione Cast non valida. Ho eseguito il debug ed è nel punto in cui Dapper chiama GetValueil reso SqlDataReader.

Il tipo di ritorno GetValueè Object, controllandolo nel debugger show è un decimale inscatolato.

Se cambio la selezione in SELECT CAST(@@IDENTITY as int), il ritorno di GetValue è un int box e l'eccezione non viene generata.

La colonna Id è sicuramente di tipo int; Perché dovrebbe SELECT @@IDENTITYrestituire un decimale?

Alcune informazioni aggiuntive:

  • Il database è nuovo di zecca.
  • La tabella Clienti è l'unico oggetto che ho aggiunto ad essa. Non ci sono altre tabelle (utente), viste, trigger o procedure memorizzate nel database.
  • Ci sono 10 righe nel database, gli ID sono 1,2,3,4,5,6,7,8,9,10 (cioè la colonna non è oltre i limiti di un int).

La mia definizione di tabella è

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]

Hai dei trigger nella tabella Clienti?
Richard,

3
Vorrei usare SCOPE_IDENTITY () invece di @@ IDENTITY. @@ IDENTITY ti darà l'ultimo valore di identità creato da qualsiasi cosa sulla connessione corrente, al contrario del tuo ambito attuale. Quindi, come ha suggerito Richard, un trigger che modifica un'altra tabella e genera un'identità influenzerebbe il ritorno di @@ IDENTITY.
Nick Chammas,

Non ci sono trigger nel DB. È un nuovo database e la tabella Clienti è l'unica tabella che ho creato.
Greg B,

@Greg B: questo è il tipo di ritorno della funzione. Ti aspettavi int / bigint come tipo di ritorno (come suggerisce la domanda) o stai mettendo in dubbio la scelta di MS per questa funzione?
Marian,

Risposte:


28
  1. L'identità @@ restituisce un numero (38,0) . Dovrai lanciarlo per portarlo a un int.

    SELEZIONA CAST (@@ identità AS INT)

  2. Inoltre, prova a utilizzare scope_identity invece. Se sono presenti trigger nella tabella Clienti, è possibile che si ottenga l'ultima identità da un'altra tabella.

  3. Infine, poiché stai usando dapper , ti consigliamo di racchiudere tutto ciò all'interno di una procedura memorizzata in modo da assicurarti di eseguire l'inserimento e quindi la selezione sull'identità nello stesso batch.

    Teoricamente, dovrebbe funzionare la maggior parte del tempo per eseguire entrambi da soli. Ma potrebbero sorgere problemi se si deve andare al database due volte. (Ad esempio, come funziona con il pool di connessioni? Che dire delle connessioni interrotte? Ecc.) Se si lancia tutto in una procedura memorizzata, non sarà necessario preoccuparsi di quello sforzo aggiuntivo lungo la strada.


Grazie per # 3. Non c'è modo di definire un batch in un'istruzione SQL ad hoc ?
Greg B,

Lo stavo dando un'altra occhiata. Se includi tutte le istruzioni in una chiamata, è tutto un batch. Se si suddividono le dichiarazioni in chiamate separate, le cose potrebbero essere difettose.
Richard,

3
+1 per raccomandare SCOPE_IDENTITY ()
Andrew Bickerton,

10

Crea tabella dice:

" IDENTITÀ

Indica che la nuova colonna è una colonna identità. Quando viene aggiunta una nuova riga alla tabella, Microsoft® SQL Server ™ fornisce un valore univoco e incrementale per la colonna. Le colonne di identità vengono comunemente utilizzate insieme ai vincoli PRIMARY KEY per fungere da identificatore di riga univoco per la tabella. La proprietà IDENTITY può essere assegnata a colonne tinyint, smallint, int, bigint, decimal (p, 0) o numeriche (p, 0). È possibile creare una sola colonna di identità per tabella. I valori predefiniti associati e i vincoli DEFAULT non possono essere utilizzati con una colonna identità. È necessario specificare sia il seme che l'incremento o nessuno dei due. Se nessuno dei due è specificato, il valore predefinito è (1,1).

seme

Valore utilizzato per la prima riga caricata nella tabella?

incremento

È stato caricato il valore incrementale aggiunto al valore di identità della riga precedente? "

Quindi la funzione di sistema @@ identità dovrà far fronte al tipo più coprente.


Ed è per questo che ritorna numericin quanto ha la gamma più ampia ..? Grazie
Greg B,

3
Una funzione non può avere più di un tipo restituito. Dovrà utilizzare il tipo più largo per includere ogni possibilità.
Marian,

6

"Perché SELECT @@ IDENTITY restituisce un decimale"

Perché potrebbe essere troppo grande per essere inserito in un int- non corrisponde al tipo di colonna identità ma come dice Richard restituisce un valore numerico (38,0) ( numerice decimal sono sinonimi )

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.