Mengapa `SELECT @@ IDENTITY` mengembalikan angka desimal?

24

Saya menggunakan Dapper untuk menjalankan kueri berikut terhadap contoh SQL Server 2008 R2 Express dari aplikasi 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

Panggilan untuk connection.Query<int>(sql, ...)melempar Pengecualian Pemain Tidak Valid. Saya sudah men-debug dan itu pada titik di mana Dapper memanggil GetValueyang dikembalikan SqlDataReader.

Jenis kembalinya GetValueadalah Object, memeriksanya di acara debugger itu adalah desimal kotak.

Jika saya mengubah pilih ke SELECT CAST(@@IDENTITY as int), kembalinya GetValue adalah kotak int dan pengecualian tidak dibuang.

Kolom Id jelas bertipe int; Mengapa SELECT @@IDENTITYmengembalikan desimal?

Beberapa informasi tambahan:

  • Basis datanya baru.
  • Tabel Pelanggan adalah satu-satunya objek yang saya tambahkan ke dalamnya. Tidak ada tabel (pengguna) lain, pandangan, pemicu atau prosedur tersimpan dalam database.
  • Ada 10 baris dalam database, ada Id 1,2,3,4,5,6,7,8,9,10 (yaitu kolom tidak di luar batas int).

Definisi tabel saya adalah

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
sumber
Apakah Anda memiliki pemicu di tabel Pelanggan?
Richard
3
Saya akan menggunakan SCOPE_IDENTITY () alih-alih @@ IDENTITY. @@ IDENTITY akan memberi Anda nilai identitas terakhir yang dibuat oleh apa pun pada koneksi saat ini, yang bertentangan dengan ruang lingkup Anda saat ini. Jadi, seperti yang disarankan Richard, pemicu memodifikasi tabel lain dan menghasilkan identitas akan memengaruhi pengembalian @@ IDENTITY.
Nick Chammas
Tidak ada pemicu dalam DB. Ini database baru dan tabel Pelanggan adalah satu-satunya tabel yang saya buat.
Greg B
@Reg B: ini adalah tipe pengembalian fungsi. Apakah Anda mengharapkan int / bigint sebagai tipe pengembalian (seperti yang disarankan pertanyaan) atau Anda mempertanyakan pilihan MS untuk fungsi ini?
Marian

Jawaban:

28
  1. @@ identitas mengembalikan angka (38,0) . Anda harus membuangnya untuk mencapai int.

    SELECT CAST (@@ identity AS INT)

  2. Selain itu, coba gunakan scope_identity sebagai gantinya. Jika Anda memiliki pemicu pada tabel Pelanggan, Anda mungkin mendapatkan identitas terakhir dari tabel lain.

  3. Akhirnya, karena Anda menggunakan necis , Anda harus membungkus semua itu di dalam prosedur tersimpan sehingga Anda dijamin untuk mengeksekusi memasukkan dan kemudian pilih pada identitas dalam batch yang sama.

    Secara teoritis, itu harus bekerja sebagian besar waktu untuk mengeksekusi keduanya sendiri. Tetapi masalah bisa muncul jika Anda harus pergi ke database dua kali. (Misalnya bagaimana ini bekerja dengan koneksi pooling? Bagaimana dengan koneksi yang terputus? Dll.) Jika Anda hanya membuang semuanya dalam prosedur tersimpan, Anda tidak perlu khawatir tentang upaya ekstra di jalan.

Richard
sumber
Terima kasih untuk # 3. Apakah tidak ada cara untuk mendefinisikan kumpulan dalam pernyataan SQL adhoc ?
Greg B
Saya melihat lagi. Jika Anda memasukkan semua pernyataan dalam satu panggilan, semuanya adalah satu kumpulan. Jika Anda memecah pernyataan menjadi panggilan terpisah, hal-hal bisa menjadi buggy.
Richard
3
+1 untuk merekomendasikan SCOPE_IDENTITY ()
Andrew Bickerton
10

Buat tabel mengatakan:

" IDENTITAS

Menunjukkan bahwa kolom baru adalah kolom identitas. Ketika baris baru ditambahkan ke tabel, Microsoft® SQL Server ™ memberikan nilai tambahan yang unik untuk kolom. Kolom identitas umumnya digunakan bersama dengan batasan PRIMARY KEY untuk berfungsi sebagai pengidentifikasi baris unik untuk tabel. Properti IDENTITY dapat ditetapkan ke kolom tinyint, smallint, int, bigint, desimal (p, 0), atau numerik (p, 0). Hanya satu kolom identitas yang dapat dibuat per tabel. Default batas dan batasan DEFAULT tidak dapat digunakan dengan kolom identitas. Anda harus menentukan seed dan increment atau keduanya. Jika tidak ada yang ditentukan, standarnya adalah (1,1).

benih

Apakah nilai yang digunakan untuk baris pertama dimuat ke dalam tabel.

kenaikan

Apakah nilai tambahan ditambahkan ke nilai identitas dari baris sebelumnya yang dimuat. "

Jadi fungsi sistem @@ identitas harus mengatasi jenis yang paling mencakup.

Marian
sumber
Dan inilah mengapa ia kembali numerickarena memiliki jangkauan terluas ..? Terima kasih
Greg B
3
Fungsi tidak dapat memiliki lebih dari satu jenis pengembalian. Itu harus menggunakan tipe terluas untuk memasukkan setiap kemungkinan.
Marian
6

"Mengapa SELECT @@ IDENTITY mengembalikan desimal"

Karena mungkin terlalu besar untuk dimasukkan dalam int- itu tidak cocok dengan jenis kolom identitas tetapi seperti kata Richard mengembalikan numerik (38,0) ( numericdan decimal sinonim )

Jack Douglas
sumber