Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
Ролг Хупин
Member

Откуда: Чебаркуль
Сообщений: 1612
Есть вызов

strCmd = @"insert into [dbo].[logs](msg) values(@msg); select SCOPE_IDENTITY();";
// ...
object objid = cmd1.ExecuteScalar();
if (objid != DBNull.Value)


На инсерт есть триггер, который проверяет что-то и делает
--...
IF @numrows>=1
BEGIN
	ROLLBACK TRAN;
	RAISERROR('Msg cannot be added', 16, 1);
	RETURN;
END


Этот триггер не генерирует Exception.
Каждый раз, даже когда триггер не добавляет запись и делает роллбек
здесь
object objid = cmd1.ExecuteScalar();

возвращается 2

Что не так?
5 окт 17, 16:52    [20845977]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
BlackEric
Member

Откуда:
Сообщений: 699
Ролг Хупин,

А что вернет Select * from log?
Там мах id не 2?
SCOPE_IDENTITY (Transact-SQL) - это читали?
5 окт 17, 17:04    [20846032]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
Ролг Хупин
Member

Откуда: Чебаркуль
Сообщений: 1612
BlackEric
Ролг Хупин,

А что вернет Select * from log?
Там мах id не 2?
SCOPE_IDENTITY (Transact-SQL) - это читали?


нет, там не 2, а 258
читал, а толку? вопрос не в этом.
Если руками выполняю в ССМС тот же запрос, выловленный в профайлере получаю:

Msg 50000, Level 16, State 1, Procedure tr_дщп, Line 44 [Batch Start Line 15]
Msg cannot be added
Msg 3609, Level 16, State 1, Line 16
The transaction ended in the trigger. The batch has been aborted.


А в c# коде нет Exception и создается впечатление, что запрос отработал успешно.
5 окт 17, 17:12    [20846075]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
buser
Member

Откуда: Санкт-Петербург
Сообщений: 4077
Ролг Хупин, тело триггера покажите пож.
5 окт 17, 17:50    [20846175]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
BlackEric
Member

Откуда:
Сообщений: 699
Я воспроизвел

Таблица:
Create Table logs
(
id int primary key identity(1,1),
msg nvarchar(MAX)
)
Go


Инсерты:
insert into logs(msg)values('qaz')
insert into logs(msg)values('qaz')
insert into logs(msg)values('edc')
insert into logs(msg)values('rfv')


Триггер:
CREATE TRIGGER dbo.AI_CheckSingleRow
   ON  [dbo].[logs]
   AFTER INSERT, UPDATE
AS 
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for trigger here
	DECLARE @numrows int;
	SET @numrows = 0;

	Select @numrows = count(*) from inserted 

	IF @numrows > 1
	BEGIN
		ROLLBACK TRAN;
		RAISERROR('Msg cannot be added', 16, 1);
		RETURN;
	END

END
GO


Запрос падающий из студии:
Update logs
Set msg = '123'
where msg = 'qaz'
Go
Select SCOPE_IDENTITY()


Оно же из шарпа нормально отрабатывает (не падает):
static void Main(string[] args)
        {
            string connectionString = "Data Sou...";

            SqlDataReader rdr = null;
            SqlConnection con = null;
            SqlCommand cmd = null;

            try
            {
                con = new SqlConnection(connectionString);
                con.Open();

                string commandText = "Select SERVERPROPERTY('productversion'), @@servername";

                cmd = new SqlCommand(commandText);
                cmd.Connection = con;

                rdr = cmd.ExecuteReader();

                while (rdr.Read())
                {
                    Console.WriteLine(rdr[0].ToString());
                    Console.WriteLine(rdr[1].ToString());
                }

                rdr.Close();

                ////=============

                commandText = "Update logs Set msg = '123' where msg = 'qaz'; Select SCOPE_IDENTITY()";

                objid = cmd.ExecuteScalar();
                if (objid != DBNull.Value)
                    Console.WriteLine(objid.ToString());
                else
                    Console.WriteLine("NULL!!!"); 

                ////=============


            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                if (rdr != null)
                    rdr.Close();

                if (con != null && con.State == ConnectionState.Open)
                    con.Close();
            }

            Console.Read();

        }
5 окт 17, 18:27    [20846263]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
BlackEric
Member

Откуда:
Сообщений: 699
Не сорри, падает как положено
5 окт 17, 18:30    [20846271]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
buser
Member

Откуда: Санкт-Петербург
Сообщений: 4077
BlackEric, а попробуйте изменить триггер
+
ALTER TRIGGER dbo.AI_CheckSingleRow
   ON  [dbo].[logs]
   AFTER INSERT, UPDATE
AS 
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	-- SET NOCOUNT ON;

    -- Insert statements for trigger here
	DECLARE @numrows int;
	SET @numrows = 0;

	Select @numrows = count(*) from inserted 
        select @numrows
	IF @numrows > 1
	BEGIN
		ROLLBACK TRAN;
		RAISERROR('Msg cannot be added', 16, 1);
		RETURN;
	END

END
GO
5 окт 17, 18:41    [20846286]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 3453
Если для таблицы не предполагается использовать MERGE, то вовсе не нужно селектить количество строк в inserted - достаточно проверить @@rowcount до установки set nocount on (в случае merge ситуация другая).
А исключение пробрасывается вполне нормально:
create table dbo.Test (n int)
go
create trigger dbo.TrTest on dbo.Test after insert, update
as
begin
  raiserror('rowcount=%d', 0, 0, @@rowcount) with nowait;
  set nocount on;
  rollback;
  raiserror('ARRGH!!111', 16, 1);
end;
go

static void Main()
{
  using (var cnn = new SqlConnection("Data Source=.;Initial Catalog=stuff;Integrated Security=True"))
  using (var cmd = new SqlCommand(@"
    insert into dbo.Test
      select number
      from master..spt_values
      where type='P' and number between 1 and 123;
      select 1;",
    cnn))
  {
    cnn.InfoMessage += (s, e) => Console.WriteLine("Server message: {0}", e.Message);
    cnn.Open();
    try
    {
      Console.WriteLine("Scalar result: {0}", cmd.ExecuteScalar());
    }
    catch (Exception e)
    {
      Console.WriteLine("{0}: {1}", e.GetType(), e.Message);
    }
  }
}

в консоли:

Server message: rowcount=123
System.Data.SqlClient.SqlException: ARRGH!!111
The transaction ended in the trigger. The batch has been aborted.
6 окт 17, 06:20    [20846966]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
Ролг Хупин
Member

Откуда: Чебаркуль
Сообщений: 1612
BlackEric
Не сорри, падает как положено


а у меня нет эскцепции
6 окт 17, 12:34    [20847852]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 695
Ролг Хупин,

Подключите Profiler и посмотрите попадает ли сервер в блок где у вас raiserror
6 окт 17, 23:26    [20849973]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 3453
felix_ff
Ролг Хупин,

Подключите Profiler и посмотрите попадает ли сервер в блок где у вас raiserror

Не нужен никакой профайлер - raiserror с severity<=10 не прерывает процесс выполнения, и не попадает в блок catch, достаточно его с опцией nowait (чтобы сообщение возвращалось сразу же, а не по окончании всего батча) поместить в блок с rollback, и ловить сообщения от сервера - см. выше мой код.
7 окт 17, 04:57    [20850259]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
Ролг Хупин
Member

Откуда: Чебаркуль
Сообщений: 1612
Сон Веры Павловны
felix_ff
Ролг Хупин,

Подключите Profiler и посмотрите попадает ли сервер в блок где у вас raiserror

Не нужен никакой профайлер - raiserror с severity<=10 не прерывает процесс выполнения, и не попадает в блок catch, достаточно его с опцией nowait (чтобы сообщение возвращалось сразу же, а не по окончании всего батча) поместить в блок с rollback, и ловить сообщения от сервера - см. выше мой код.


у меня 16
9 окт 17, 12:02    [20854008]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 3453
Ролг Хупин
у меня 16

Я видел. Severity>10 - для выбрасывания ошибок, и их обработки в блоке catch (если нужно), severity<=10 - для вывода сообщений.
9 окт 17, 12:05    [20854015]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
Ролг Хупин
Member

Откуда: Чебаркуль
Сообщений: 1612
Сон Веры Павловны
Ролг Хупин
у меня 16

Я видел. Severity>10 - для выбрасывания ошибок, и их обработки в блоке catch (если нужно), severity<=10 - для вывода сообщений.


Нашел, где я лоханулся,хотя до конца так и не понял причину:

во время отладки триггера оставил пару выборок типа
select count(*) as totalrows from ....
select count(*) as totalrows2 from ....

а после них уже делаю
IF @numrows>=1
BEGIN
	ROLLBACK TRAN;
	RAISERROR('Msg cannot be added', 16, 1);
	RETURN;
END
9 окт 17, 13:08    [20854278]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
Ролг Хупин
Member

Откуда: Чебаркуль
Сообщений: 1612
Ролг Хупин
Сон Веры Павловны
пропущено...

Я видел. Severity>10 - для выбрасывания ошибок, и их обработки в блоке catch (если нужно), severity<=10 - для вывода сообщений.


Нашел, где я лоханулся,хотя до конца так и не понял причину:

во время отладки триггера оставил пару выборок типа
select count(*) as totalrows from ....
select count(*) as totalrows2 from ....

а после них уже делаю
IF @numrows>=1
BEGIN
	ROLLBACK TRAN;
	RAISERROR('Msg cannot be added', 16, 1);
	RETURN;
END




и это в SSMS и выборки делает и роллбэчится, а при вызове из шарпа тихо отрабатывает и выдает 2 и никакого роллбэка
9 окт 17, 13:14    [20854297]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
buser
Member

Откуда: Санкт-Петербург
Сообщений: 4077
Ролг Хупин, роллбак происходит... брехня. не происходит он только если @@rowcount определяется после select count(*)
И да... тах работает скаляр. Получил результат и досвидос... если нужна такого рода богодельня - пользуйте костыли
9 окт 17, 13:52    [20854470]     Ответить | Цитировать Сообщить модератору
 Re: c#->SQLServer: Нет Exception при роллбэке в триггере  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 695
Ролг Хупин,

ExecuteScalar обрабатывает одну колонку первой строки результирующего набора.
Если возвращаете множественные резалтсеты используйте ExecuteReader()
9 окт 17, 13:53    [20854477]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить