Prathap Gangireddy Ответов: 1

Ошибка в строке транзакции отката


Error appears when I uncomment Rollback transaction line after OutputID=-1

I want to rollback the transaction if any of the serial number is not matching for a particular OrderID.

Can you please help me where am i going wrong with the transactions. Begin and Commit Statements looks fine for me.Verified all the begin commit statements through out the proc


Ниже приведена ошибка

Количество транзакций после выполнения указывает на несоответствие числа операторов BEGIN и COMMIT. Предыдущий отсчет = 0, Текущий отсчет = 1


ALTER PROC dbo.UpdatePartnerSerialNumbersBatchDetails
  @OrderID             INT
, @SerialNumberDetails XML = NULL
, @SerialNumbersCount  INT
, @UploadedBy          VARCHAR(50)
, @UploadedDate        DATETIME
, @OutputID            INT OUT
AS
BEGIN
  
  SET XACT_ABORT, NOCOUNT ON;

  BEGIN TRY
    DECLARE @BatchCount INT;

    IF @SerialNumbersCount <> (SELECT TOP 1
                                      OrderQty
                               FROM   OrderMaster
                               WHERE  OrderID = @OrderID
                                      AND IsDeleted = 0)
    BEGIN
      SET @OutputID = -2;    
    END;
    ELSE
    BEGIN
      BEGIN TRANSACTION SerialNumbers;

      UPDATE
            dbo.PartnerSerialNumbers
      SET
            BatchNo = T.N.value('(BatchNo/text())[1]', 'varchar(50)')
          , DataUploadfromPartner = 1
          , ExpiryDate = T.N.value('(ExpiryDate/text())[1]', 'Datetime')
          , SerialNoStatus = 'O'
          , UploadedBy = @UploadedBy
          , UploadedDate = @UploadedDate
      FROM  @SerialNumberDetails.nodes('Root/SerialNumberDetails') AS T(N)
      WHERE OrderID = @OrderID
            AND SerialNo = T.N.value('(SerialNumber/text())[1]', 'varchar(50)');

      SET @BatchCount = @@ROWCOUNT;

      IF @BatchCount <> (SELECT TOP 1
                                OrderQty
                         FROM   OrderMaster
                         WHERE  OrderID = @OrderID
                                AND IsDeleted = 0)
      BEGIN
       
        SET @OutputID = -1;    
        ROLLBACK TRANSACTION SerialNumbers;
      END;
      ELSE
      BEGIN
        SET @OutputID = 1;

        UPDATE
              OrderMaster
        SET
              DataUploadfromPartner = 1
        WHERE OrderID = @OrderID;

        INSERT INTO SerialnumbersLogDetails
          (
            OrderID
          , SerialNo
          , GTINCode
          , OrderSentDate
          , OrderorPartner
          , BatchNo
          , ExpiryDate
          )
        SELECT
              OrderID
            , SerialNo
            , GTINCode
            , NULL
            , 'Partner'
            , BatchNo
            , ExpiryDate
        FROM  PartnerSerialNumbers
        WHERE OrderID = @OrderID;
      END;

      
      COMMIT TRANSACTION SerialNumbers;
    END;
  END TRY
  BEGIN CATCH    
    SET @OutputID = 0;

    IF @@trancount > 0 ROLLBACK TRANSACTION SerialNumbers;
  END CATCH;
END;


Что я уже пробовал:

Когда я прокомментировал это
BEGIN
       
        SET @OutputID = -1;    
       -- ROLLBACK TRANSACTION SerialNumbers;
      END;


Это прекрасно работает.

Richard Deeming

А ошибка есть?

Prathap Gangireddy

Извините..обновил вопрос

0x01AA

Не должно быть COMMIT TRANSACTION SerialNumbers; быть в квартале наверху? Для меня это выглядит так, как будто вы совершаете даже после отката.

Prathap Gangireddy

Это обычный код, который я пишу большую часть времени..синтаксически все кажется прекрасным..но когда я пытаюсь отправить данные из переднего плана в хранимую процедуру, он выдает ошибку. Еще я пробовал с фиктивными данными в management studio и он возвращает -1 без каких-либо проблем

1 Ответов

Рейтинг:
1

Richard Deeming

Хотя это не совсем ясно из документация[^], ROLLBACK TRANSACTION не завершает хранимую процедуру. Заявления после того, как ROLLBACK продолжайте выполнять.

Следующим оператором для выполнения будет COMMIT TRANSACTION строка, которая завершится ошибкой:

Цитата:
Msg 3902, Уровень 16, Состояние 1, ...
Запрос commit transaction не имеет соответствующей начинать сделки.
Однако это должно быть поймано и обработано вашим CATCH блок. Но лучше было бы поставить Return; заявление после того, как ROLLBACK, так что процедура не пытается зафиксировать транзакцию.

Я подозреваю, что код, вызывающий эту хранимую процедуру, также использует транзакцию, которая вызывает CATCH блок, чтобы попытаться откатить назад SerialNumbers транзакция, которая уже была откатана. Но это все еще не приводит к той же ошибке для меня.

Если добавить Return; оператор не устраняет проблему, возможно, вы могли бы показать код, который вызывает эту процедуру?


Prathap Gangireddy

Ричард..я уже пробовал с return statement..все равно он выдает ту же ошибку..

Richard Deeming

Это определенно звучит как проблема с кодом, вызывающим хранимую процедуру. Что произойдет, если вы выполните процедуру через SQL Server Management Studio без каких-либо дополнительных транзакций?

Prathap Gangireddy

я запустил эту процедуру в среде SQL Server Management Studio..она работает нормально и возвращает -1 без каких-либо ошибок

Richard Deeming

Итак, как я уже сказал, это связано с кодом, вызывающим процедуру, а не с самой процедурой.

Prathap Gangireddy

Все остальные сценарии, где OutputID возвращает -2,1 с теми же данными, работают нормально. но вот его кидает ошибку

Richard Deeming

Итак, как я уже сказал, это связано с кодом, вызывающим процедуру, а не с самой процедурой.

Вы не показали нам код, который не работает.

Prathap Gangireddy

public int UpdatePartnerSerialNumbersBatchDetails(PartnerSerialNumbersBatchDetails objMaster)
{
var outputID = новый SqlParameter("OutputID", SqlDbType.Int) { Direction = System.Data.ParameterDirection.Выход };
пробовать
{
результат инт = _db.Базы данных.ExecuteSqlCommand("UpdatePartnerSerialNumbersBatchDetails @OrderID,@SerialNumberDetails,@SerialNumbersCount,@UploadedBy,@UploadedDate,@OutputID out",
новый SqlParameter("OrderID", SqlDbType.Int) { Value = objMaster.Кодзаказа },
новый SqlParameter("SerialNumberDetails", SqlDbType.Xml) { Value = objMaster.SerialNumberDetails ?? (объект)DBNull.Ценность },
новый SqlParameter("SerialNumbersCount", SqlDbType.Int) { Value = objMaster.SerialNumbersCount },
новый SqlParameter("UploadedBy", SqlDbType.VarChar, 50) { Value = objMaster.UploadedBy },
новый SqlParameter("UploadedDate", SqlDbType.DateTime) { Value = objMaster.UploadedDate }, outputID);

_db.Метод SaveChanges();

return (int)outputID.Value;

}
поймать (исключение бывший)
{
строка msg = ex.Message + ex.InnerException.Метод toString();
возвращает 0;
}
}

Richard Deeming

Рамки сущности обертывания ExecuteSqlCommand вызовите транзакцию.

Вы можете избежать этого, пройдя мимо TransactionalBehavior.DoNotEnsureTransaction в качестве первого параметра:

int result = _db.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction, "UpdatePartnerSerialNumbersBatchDetails @OrderID,@SerialNumberDetails,@SerialNumbersCount,@UploadedBy,@UploadedDate,@OutputID out", ...


В качестве альтернативы используйте RAISERROR или THROW внутри хранимой процедуры, чтобы гарантировать, что любые ошибки распространяются обратно к клиенту, так что EF знает, что не нужно пытаться зафиксировать транзакцию.

0x01AA

Разве это не просто то, что он совершает даже после отката?

Richard Deeming

Он все еще получает ту же ошибку даже после добавления a return после rollback Вот почему я подозреваю, что это проблема с вызывающим кодом.

0x01AA

В любом случае "возврат" не нужен в том случае, если вы помещаете "фиксацию" в блок (начало/конец), где она логически принадлежит.
Или я что-то упускаю из виду?

Richard Deeming

Если commit был в пределах else блок, а затем return в этом нет необходимости.

0x01AA

Спасибо :-)

Извините, что беспокою вас так сильно. Еще один вопрос:
Часто ли ставят точку с запятой после первого "END" перед "ELSE", как это IF BEGIN ... END;ELSE BEGIN END;?

Еще раз извините

Richard Deeming

Завершение операторов будет точкой с запятой было рекомендовано в течение длительного времени и требуется, когда вы используете CTE. Microsoft продолжает угрожать сделать его обязательным везде в "будущей версии"; но они говорят это с 2005 года.

Ставим точку с запятой перед ELSE мне это кажется странным, но все работает, как и ожидалось.

0x01AA

Еще раз большое вам спасибо и извините за задержку. Обычно я не получаю уведомления от CP:(