Warum gibt SELECT IDENTITY eine Dezimalzahl zurück?

24

Ich verwende Dapper , um die folgende Abfrage für eine SQL Server 2008 R2 Express-Instanz aus einer ASP.NET MVC 3-Anwendung (.NET 4.0) auszuführen.

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

SELECT @@IDENTITY

Der Aufruf von connection.Query<int>(sql, ...)löst eine ungültige Besetzungsausnahme aus. Ich habe es ausgetestet und es ist an der Stelle , wo Dapper Anrufe GetValueauf die zurück SqlDataReader.

Der Rückgabetyp von GetValueist Object, es in der Debugger-Show zu überprüfen, es ist eine Boxed Decimal.

Wenn ich die Auswahl auf SELECT CAST(@@IDENTITY as int)ändere, ist die Rückgabe von GetValue ein Boxed Int und die Ausnahme wird nicht geworfen.

Die ID-Spalte ist definitiv vom Typ int. Warum sollte SELECT @@IDENTITYeine Dezimalzahl zurückgegeben werden?

Einige zusätzliche Informationen:

  • Die Datenbank ist brandneu.
  • Die Customers-Tabelle ist das einzige Objekt, das ich hinzugefügt habe. Die Datenbank enthält keine anderen (Benutzer-) Tabellen, Ansichten, Trigger oder gespeicherten Prozeduren.
  • Die Datenbank enthält 10 Zeilen, die IDs sind 1,2,3,4,5,6,7,8,9,10 (dh die Spalte überschreitet nicht die Grenzen eines Int).

Meine Tabellendefinition ist

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
quelle
Haben Sie irgendwelche Trigger auf dem Customers-Tisch?
Richard
3
Ich würde SCOPE_IDENTITY () anstelle von @@ IDENTITY verwenden. Mit @@ IDENTITY erhalten Sie den letzten Identitätswert, der von einem Element in der aktuellen Verbindung erstellt wurde, im Gegensatz zu Ihrem aktuellen Gültigkeitsbereich. Ein Trigger, der eine andere Tabelle ändert und eine Identität erzeugt, würde also, wie Richard vermutet, die Rückgabe von @@ IDENTITY beeinflussen.
Nick Chammas
Es gibt keine Trigger in der DB. Es ist eine neue Datenbank und die Customers-Tabelle ist die einzige Tabelle, die ich erstellt habe.
Greg B
@Greg B: Dies ist der Rückgabetyp der Funktion. Haben Sie mit int / bigint als Rückgabetyp gerechnet (wie die Frage nahelegt) oder stellen Sie die MS-Auswahl für diese Funktion in Frage?
Marian

Antworten:

28
  1. @@ identity gibt eine Zahl (38,0) zurück . Sie müssen es wirken, um es zu einem int zu bekommen.

    SELECT CAST (@@ Identität AS INT)

  2. Verwenden Sie stattdessen auch scope_identity. Wenn die Customers-Tabelle Auslöser enthält, wird möglicherweise die letzte Identität von einer anderen Tabelle abgerufen.

  3. Da Sie dapper verwenden , sollten Sie all das in eine gespeicherte Prozedur einschließen , damit Sie garantiert die Einfügung ausführen und dann die Identität im selben Stapel auswählen können.

    Theoretisch sollte es die meiste Zeit funktionieren, beide alleine auszuführen. Es können jedoch Probleme auftreten, wenn Sie zweimal zur Datenbank gehen müssen. (ZB wie funktioniert das mit dem Verbindungspooling? Was ist mit unterbrochenen Verbindungen? Usw.) Wenn Sie einfach alles in eine gespeicherte Prozedur werfen, müssen Sie sich später nicht mehr um diesen zusätzlichen Aufwand kümmern.

Richard
quelle
Danke für # 3. Gibt es keine Möglichkeit, einen Stapel in einer Ad-hoc- SQL-Anweisung zu definieren ?
Greg B
Ich habe es mir noch einmal angesehen. Wenn Sie alle Anweisungen in einem Aufruf enthalten, handelt es sich um einen Stapel. Wenn Sie die Anweisungen in separate Aufrufe aufteilen, kann es zu Fehlern kommen.
Richard
3
+1 für das Empfehlen von SCOPE_IDENTITY ()
Andrew Bickerton
10

Tabelle erstellen sagt:

" IDENTITÄT

Gibt an, dass die neue Spalte eine Identitätsspalte ist. Wenn der Tabelle eine neue Zeile hinzugefügt wird, stellt Microsoft® SQL Server ™ einen eindeutigen inkrementellen Wert für die Spalte bereit. Identitätsspalten werden häufig in Verbindung mit PRIMARY KEY-Einschränkungen verwendet, um als eindeutige Zeilenbezeichnung für die Tabelle zu dienen. Die IDENTITY-Eigenschaft kann den Spalten tinyint, smallint, int, bigint, decimal (p, 0) oder numeric (p, 0) zugewiesen werden. Pro Tabelle kann nur eine Identitätsspalte erstellt werden. Gebundene Standardwerte und DEFAULT-Einschränkungen können nicht mit einer Identitätsspalte verwendet werden. Sie müssen sowohl den Startwert als auch das Inkrement oder keines angeben. Wenn keines angegeben ist, ist der Standardwert (1,1).

Samen

Wird der Wert für die allererste in die Tabelle geladene Zeile verwendet.

Zuwachs

Wird der inkrementelle Wert zum Identitätswert der vorherigen geladenen Zeile addiert? "

Die Systemfunktion @@ identity muss sich also mit dem umfassendsten Typ auseinandersetzen.

Marian
quelle
Und aus diesem Grund kehrt es zurück, numericda es die größte Reichweite hat. Vielen Dank
Greg B
3
Eine Funktion kann nicht mehr als einen Rückgabetyp haben. Es muss der breiteste Typ verwendet werden, um alle Möglichkeiten einzuschließen.
Marian
6

"Warum sollte SELECT @@ IDENTITY eine Dezimalzahl zurückgeben?"

Da es möglicherweise zu groß ist, um in eine zu passen int, stimmt es nicht mit dem Typ der Identitätsspalte überein, gibt aber, wie Richard sagt, eine Zahl (38,0) zurück ( numericund decimal sind Synonyme ).

Jack Douglas
quelle