Saya ingin menampilkan kembali pengecualian yang sama di SQL Server yang baru saja terjadi di blok percobaan saya. Saya dapat memberikan pesan yang sama tetapi saya ingin memberikan kesalahan yang sama.
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Tags.tblDomain (DomainName, SubDomainId, DomainCode, Description)
VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
declare @severity int;
declare @state int;
select @severity=error_severity(), @state=error_state();
RAISERROR(@@Error,@ErrorSeverity,@state);
ROLLBACK TRANSACTION
END CATCH
RAISERROR(@@Error, @ErrorSeverity, @state);
Baris ini akan menunjukkan kesalahan, tetapi saya ingin fungsionalitas seperti itu. Ini menimbulkan kesalahan dengan nomor kesalahan 50000, tetapi saya ingin nomor kesalahan dilemparkan yang saya lewati @@error
,
Saya ingin menangkap kesalahan ini tidak di bagian depan.
yaitu
catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}
Saya ingin fungsi ini. yang tidak dapat dicapai dengan menggunakanraiseerror
. Saya tidak ingin memberikan pesan kesalahan khusus di bagian belakang.
RAISEERROR
harus mengembalikan kesalahan yang disebutkan di bawah ini ketika saya melewati ErrorNo untuk dilempar ke dalam tangkapan
Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,
Baris 14 Pelanggaran batasan UNIQUE KEY 'UK_DomainCode'. Tidak dapat memasukkan kunci duplikat dalam objek 'Tags.tblDomain'. Pernyataan tersebut telah dihentikan.
EDIT:
Apa yang bisa menjadi kekurangan dari tidak menggunakan blok try catch jika saya ingin pengecualian ditangani di frontend mengingat prosedur tersimpan berisi banyak kueri yang perlu dijalankan?
raiserror
, yang berbeda dari bagaimana c # keluar setelah athrow
. Jadi saya menambahkan bagianreturn
dalamcatch
karena saya ingin mencocokkan perilaku itu.RAISERROR()
dok . Keparahan ≥11 hanya melompat ke satuCATCH
blok jika berada di dalamTRY
blok. Jadi Anda harus memilikiBEGIN TRY…END CATCH
sekitar kode jika Anda inginRAISERROR()
mempengaruhi kontrol aliran.SQL 2012 memperkenalkan pernyataan lemparan:
http://msdn.microsoft.com/en-us/library/ee677615.aspx
BEGIN TRY BEGIN TRANSACTION ... COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION; THROW END CATCH
sumber
ROLLBACK
telepon itu penting! Tanpanya Anda mungkin mendapatkan fileSQLException: Cannot roll back THROW
.Melempar kembali di dalam blok CATCH (kode pra-SQL2012, gunakan pernyataan THROW untuk SQL2012 dan yang lebih baru):
DECLARE @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(), @ErrorNumber int = ERROR_NUMBER(), @ErrorSeverity int = ERROR_SEVERITY(), @ErrorState int = ERROR_STATE(), @ErrorLine int = ERROR_LINE(), @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-'); SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage; RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
sumber
Saya pikir pilihan Anda adalah:
Pada titik tertentu, SQL mungkin akan memperkenalkan perintah reraise, atau kemampuan untuk menangkap kesalahan tertentu saja. Tapi untuk saat ini, gunakan solusi. Maaf.
sumber
Anda tidak dapat: hanya mesin yang dapat melakukan kesalahan kurang dari 50000. Yang dapat Anda lakukan hanyalah membuat pengecualian yang terlihat seperti itu ...
Silakan lihat jawaban saya di sini
Penanya di sini menggunakan transaksi sisi klien untuk melakukan apa yang dia inginkan yang menurut saya agak konyol ...
sumber
Oke, ini solusinya ... :-)
DECLARE @Error_Number INT BEGIN TRANSACTION BEGIN TRY INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish') /* Column 'Name' has unique constraint on it*/ END TRY BEGIN CATCH SELECT ERROR_NUMBER() --RAISERROR (@ErrorMessage,@Severity,@State) ROLLBACK TRAN END CATCH
Jika Anda mencatat blok tangkap, Ini tidak meningkatkan kesalahan tetapi mengembalikan nomor kesalahan sebenarnya (dan juga akan mengembalikan transaksi). Sekarang dalam kode .NET Anda, alih-alih menangkap pengecualian, jika Anda menggunakan ExecuteScalar (), Anda mendapatkan nomor kesalahan aktual yang Anda inginkan dan menunjukkan nomor yang sesuai.
Semoga ini membantu,
EDIT: - Sekadar catatan, Jika Anda ingin mendapatkan jumlah record yang terpengaruh dan mencoba menggunakan ExecuteNonQuery, solusi di atas mungkin tidak berfungsi untuk Anda. Jika tidak, saya pikir itu akan sesuai dengan apa yang Anda butuhkan. Biarkan aku tahu.
sumber
Cara untuk menghentikan eksekusi dalam prosedur tersimpan setelah kesalahan terjadi dan mengembalikan kesalahan ke program pemanggil adalah dengan mengikuti setiap pernyataan yang mungkin menimbulkan kesalahan dengan kode ini:
Saya sendiri terkejut saat mengetahui bahwa eksekusi dalam prosedur tersimpan dapat berlanjut setelah terjadi kesalahan - tidak menyadari hal ini dapat menyebabkan beberapa bug sulit dilacak.
Jenis kesalahan penanganan paralel (pra .Net) Visual Basic 6. Menantikan perintah Lempar di SQL Server 2012.
sumber
Mengingat bahwa Anda belum pindah ke tahun 2012, salah satu cara untuk mengimplementasikan penggelembungan kode kesalahan asli adalah dengan menggunakan bagian pesan teks dari pengecualian yang Anda lemparkan (ulang) dari blok catch. Ingatlah bahwa ini dapat berisi beberapa struktur, misalnya, teks XML untuk kode pemanggil Anda untuk diurai dalam blok catch-nya.
sumber
Anda juga dapat membuat prosedur penyimpanan pembungkus untuk skenario tersebut ketika Anda ingin pernyataan SQL dijalankan dalam transaksi dan memasukkan kesalahan ke kode Anda.
CREATE PROCEDURE usp_Execute_SQL_Within_Transaction ( @SQL nvarchar(max) ) AS SET NOCOUNT ON BEGIN TRY BEGIN TRANSACTION EXEC(@SQL) COMMIT TRANSACTION END TRY BEGIN CATCH DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE() ROLLBACK TRANSACTION RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState) END CATCH GO -- Test it EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2' EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2' EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'
sumber
Dari sudut pandang desain, apa gunanya memberikan pengecualian dengan nomor kesalahan asli dan pesan khusus? Untuk beberapa hal itu merusak kontrak antarmuka antara aplikasi dan database. Jika Anda ingin menangkap kesalahan asli dan menanganinya dalam kode yang lebih tinggi, jangan menanganinya di database. Kemudian saat Anda menemukan pengecualian, Anda dapat mengubah pesan yang disajikan kepada pengguna menjadi apa pun yang Anda inginkan. Saya tidak akan melakukannya, karena itu membuat kode database Anda hmm 'tidak benar'. Seperti yang dikatakan orang lain, Anda harus menentukan satu set kode kesalahan Anda sendiri (di atas 50000) dan membuangnya. Kemudian Anda dapat menangani masalah integritas ('Nilai duplikat tidak diperbolehkan') secara terpisah dari potensi masalah bisnis - 'Kode pos tidak valid', 'Tidak ada baris yang cocok dengan kriteria', dan seterusnya.
sumber
try { code(); } catch (Exception exc) { log(exc); throw; } finally { cleanup(); }
manathrow;
hanya akan memunculkan pengecualian asli, dengan konteks aslinya.