0

У меня есть хранимая процедура, которую я выполняю из VB.NET. SP должен вставлять записи в таблицу и возвращать набор вызывающему приложению. Возвращенный набор - это записи, которые были вставлены.Исключение из хранимой процедуры не попало в .NET с использованием SqlDataAdapter.Fill (DataTable)

Если ошибка INSERT не удалась, исключение поймано и повторно выбрано в SP, но я никогда не вижу исключения в своем приложении. Уровень серьезности равен 14, поэтому я должен это увидеть.

Вот хранимая процедура:

BEGIN TRY  

    BEGIN TRANSACTION 

     -- Declare local variables 
     DECLARE @DefaultCategoryID AS BIGINT = 1    -- 1 = 'Default Category' (which means no category) 
     DECLARE @DefaultWeight AS DECIMAL(18,6) = 0 
     DECLARE @InsertionDate AS DATETIME2(7) = GETDATE() 
     DECLARE @SendToWebsite AS BIT = 0      -- 0 = 'NO' 
     DECLARE @MagentoPartTypeID AS BIGINT = 1    -- For now, this is the only part type we are importing from COPICS ('simple' part type) 

     DECLARE @NotUploaded_PartStatusID AS TINYINT = 0  -- 0 = 'Not Uploaded' 
     DECLARE @Enabled_PartStatusID AS TINYINT = 1   -- 1 = 'Enabled' 
     DECLARE @Disabled_PartStatusID AS TINYINT = 2   -- 2 = 'Disabled' 


     -- Get the part numbers that will be inserted (this set will be returned to calling procedure). 
     SELECT c.PartNumber 
     FROM 
      COPICSPartFile c 
      LEFT JOIN Part p on c.PartNumber = p.PartNumber 
     WHERE 
      p.PartNumber IS NULL   

     -- Insert new records from COPICSPartFile (records that don't exist - by PartNumber - in Part table) 
     INSERT INTO Part 
      ([PartNumber] 
      ,[ReplacementPartNumber] 
      ,[ShortDescription] 
      ,[ListPrice] 
      ,[PartStatusTypeID] 
      ,[Weight] 
      ,[CategoryID] 
      ,[DateInserted] 
      ,[SendToWebsite] 
      ,[FileName] 
      ,[MagentoPartTypeID] 
      ,[PrintNumber]) 
     SELECT 
      c.PartNumber 
      ,c.ReplacementPartNumber 
      ,c.ShortDescription 
      ,c.ListPrice 
      ,CASE WHEN c.PartStatusTypeID = @Enabled_PartStatusID THEN @NotUploaded_PartStatusID ELSE @Disabled_PartStatusID END 
      ,@DefaultWeight 
      ,@DefaultCategoryID 
      ,@InsertionDate 
      ,@SendToWebsite 
      ,@FileName 
      ,@MagentoPartTypeID 
      ,c.PrintNumber 
     FROM 
      COPICSPartFile c 
      LEFT JOIN Part p on c.PartNumber = p.PartNumber 
     WHERE 
      p.PartNumber IS NULL 


    COMMIT TRANSACTION; 

END TRY 

BEGIN CATCH 

    IF @@TRANCOUNT > 0 
     ROLLBACK TRANSACTION; 

    THROW; 

END CATCH 

А вот код .net:

Try 

    'Create command 
    Dim command As New SqlCommand 
    command.CommandType = CommandType.StoredProcedure 
    conn = New SqlConnection(m_ConnectionString) 
    command.Connection = conn 
    command.CommandText = "trxInsertPartFromCOPICSPartFile" 
    With command.Parameters 
     .AddWithValue("@FileName", fileName) 
    End With 
    Dim da As New SqlDataAdapter(command) 
    Dim dt As New DataTable 
    da.Fill(dt) 

    If dt.Rows.Count > 0 Then 
     Return dt 
    Else 
     Return Nothing 
    End If 

Catch ex As SqlException 

    Dim myMessage As String = ex.Message 

Finally 
    If conn.State <> ConnectionState.Closed Then 
     conn.Close() 
    End If 
End Try 

Как я пытался выяснить, почему исключение (клавиша дублирует) не является пойманный в моем приложении, я попытался прокомментировать заявление SELECT в SP перед INSERT и вуалой. Исключение из INSERT попадает в приложение.

Может кто-нибудь объяснить мне, почему заявление SELECT вызывает это? Я знаю, что могу разбить SELECT на другой SP, но я хотел бы оставить все это одной атомной транзакцией, если это возможно. Это ожидаемое поведение? Есть ли способ обойти это?

Спасибо.

+0

Когда вы говорите, не видя исключение в приложении вы имеете в виду в пользовательском интерфейсе или войти? Или вы говорите, что точка останова не попадает? На самом деле вы ничего не делаете с исключением. Вы отбрасываете его. – TyCobb

+0

@TyCobb - Я устанавливаю точку останова там, и это не ударит, когда я отлаживаю. Первоначально я позволял исключению пузыряться до другого метода и обрабатывать его там. Просто добавлена ​​уловка для упрощения отладки. – TrailJon

+1

Вероятно, это «съедено» методом «Fill». Как насчет создания SqlDataReader, выполняющего 'command.ExecuteReader()' и используя считыватель для заполнения 'DataTable' через' Load() '? Таким образом, ошибка должна возникать в 'ExecuteReader()' и должна быть увлекательной. ** ИЛИ ** возможно, это уже не 'SqlException', выходящий из' Fill', так что просто поймайте общий «Исключение». –

ответ

1

Исключение составляет поглощение методом Fill. Вместо использования этого метода создайте , сделайте command.ExecuteReader(), а затем используйте считыватель для заполнения DataTable через Load(). Таким образом, ошибка должна произойти в методе ExecuteReader() и должна быть увлекательной. И тогда вам не понадобится SqlDataAdapter.

Try 
    'Create command 
    Dim command As New SqlCommand 
    command.CommandType = CommandType.StoredProcedure 
    conn = New SqlConnection(m_ConnectionString) 
    command.Connection = conn 
    command.CommandText = "trxInsertPartFromCOPICSPartFile" 
    With command.Parameters 
     .AddWithValue("@FileName", fileName) 
    End With 

    Dim dt As New DataTable 
    conn.Open() 
    Dim reader As SqlDataReader = command.ExecuteReader() 
    dt.Load(reader) 

    If dt.Rows.Count > 0 Then 
     Return dt 
    Else 
     Return Nothing 
    End If 

Catch ex As SqlException 

    Dim myMessage As String = ex.Message 

Finally 
    If conn.State <> ConnectionState.Closed Then 
     conn.Close() 
    End If 
End Try 

Кроме того, вы могли бы быть лучше на нескольких уровнях, если вы объедините ВЫБОР и вкладышем в одном операторе. Вы можете сделать это с помощью пункта OUTPUT, следующим образом:

INSERT INTO Part 
     ([PartNumber] 
     ,[ReplacementPartNumber] 
     ,[ShortDescription] 
     ,[ListPrice] 
     ,[PartStatusTypeID] 
     ,[Weight] 
     ,[CategoryID] 
     ,[DateInserted] 
     ,[SendToWebsite] 
     ,[FileName] 
     ,[MagentoPartTypeID] 
     ,[PrintNumber]) 
    OUTPUT INSERTED.[PartNumber] -- return the inserted values to the app code 
    SELECT 
     c.PartNumber 
     ,c.ReplacementPartNumber 
     ,c.ShortDescription 
     ,c.ListPrice 
     ,CASE WHEN c.PartStatusTypeID = @Enabled_PartStatusID 
       THEN @NotUploaded_PartStatusID 
       ELSE @Disabled_PartStatusID END 
     ,@DefaultWeight 
     ,@DefaultCategoryID 
     ,@InsertionDate 
     ,@SendToWebsite 
     ,@FileName 
     ,@MagentoPartTypeID 
     ,c.PrintNumber 
    FROM 
     COPICSPartFile c 
     LEFT JOIN Part p on c.PartNumber = p.PartNumber 
    WHERE 
     p.PartNumber IS NULL 
+1

Это, безусловно, более чистый способ написать SQL, но не решил проблему. Спасибо хоть! Я не знал, что у меня есть доступ к таблице INSERTED, как это. – TrailJon

+1

@TrailJon Спасибо за добавление рабочего кода. Я очистил формулировку предлагаемого исправления и удалил «SqlDataAdapter» из кода, поскольку он больше не нужен.Кроме того, я добавил ссылку на документацию 'OUTPUT', которую вы должны проверить. Это замечательная функция, которая была внедрена в SQL Server 2005 и дает вам доступ к таблицам «INSERTED» и «DELETED» :). –

 Смежные вопросы

  • Нет связанных вопросов^_^