Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Непонятный Exception при udate, помогите разобраться  [new]
gandalf-the-grey
Member

Откуда: НН
Сообщений: 179
Microsoft SQL Server 2005 - 9.00.5057.00 (X64) Mar 25 2011 13:33:31 Copyright (c) 1988-2005 Microsoft Corporation Standard Edition (64-bit) on Windows NT 5.2 (Build 3790: Service Pack 2)

Есть БД. В ней таблица.

CREATE TABLE [dbo].[CardEvent](
	[card_id] [int] NOT NULL,
	[status] [varchar](20) NOT NULL,
	[status_date] [datetime] NOT NULL,
	[related_card] [int] NOT NULL,
 CONSTRAINT [IX_CardEvent_unique] UNIQUE NONCLUSTERED 
(
	[card_id] ASC,
	[status] ASC,
	[status_date] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]


к ней триггер

CREATE TRIGGER [dbo].[CardEvent_ins] 
   ON  [Register].[dbo].[CardEvent]
   INSTEAD OF INSERT
AS
declare @card_id int, @status varchar(20), @st_date datetime, @rel_card int,
        @card_id_old int
declare a cursor for
   SELECT i.card_id, i.status, i.status_date, i.related_card,
          a.card_id
     FROM inserted i
left join CardEvent a on a.card_id = i.card_id and a.status = i.status and a.status_date = i.status_date

SET NOCOUNT ON

open a
while (0 = 0) begin
  fetch next from a
  into @card_id, @status, @st_date, @rel_card, @card_id_old
  if (@@fetch_status <> 0) break
  if @card_id_old is null 
   begin
    insert into CardEvent 
    values (@card_id, @status, @st_date, @rel_card)
   end
  else
   begin
      update CardEvent
         set related_card = @rel_card
       where card_id = @card_id and status = @status and status_date = @st_date
   end  
end
close a
deallocate a


Есть некая служба, которая в эту БД пихает данные.
Служба написана на Borland C++ Builder 6, для доступа к данным используются встроенные в BCB ADO-компоненты.

Служба тупо набирает некоторое количество записей в DataSet'ы Append()'ом и периодически флашит их в БД Post()'ом, вся логика в триггерах INSTEAD OF INSERT
Но есть один участок в коде службы, где ей нужно вернуться на предыдущую запись заполняемого DataSet'а и изменить одно поле.
Делается это методом Prior() датасета, а метод этот по умолчанию сперва вызывает Post().
Т.е. по сути, когда нужно изменить одно поле предыдущей записи все они постятся в таблицу (происходят insert'ы), меняется запись, Post() - тут уже происходит update. На update триггера нет, но не этом суть.
вот участок кода:

     CardEvent->Prior();
     CardEvent->Edit();
     CardEvent->FieldByName("related_card")->AsInteger = card_id;
     CardEvent->Next();


Все это работало, т.е. записи в таблицу добавлялись (если отсутсвовали), обновлялись, если менялся related_card.
Но в один прекрасный момент я понял, что работало не так, как нужно, кое-какие факторы не учитывались.
На скорую руку добавил в триггер строчку
    if @related_account <> 0

перед
      update CardEvent


после этого долго пришлось дебажить, дабы понять, в каком месте служба виснет и что это связано именно с изменением в триггере, а виснет она на
     CardEvent->Next();

Т.е. если вдруг выясняется, что надо изменить related_card предыдущей записи, делаем Prior(), при этом все записи скидываются в БД (триггер успешно отрабатывает) затем меняем запись, и на Next()'е, т.е. когда DataSet вызывет Post() и происходит update этой записи в БД, происходит Exception

EDatabaseError - Row cannot be located for updating. Some values may have been changed since it was last read

Так вот сопсно вопрос: почему при отсутствии условия в триггере (на insert причем, заметьте) все апдейтится, а при наличии - иксепшн?
8 дек 11, 17:54    [11731648]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
gandalf-the-grey
Member

Откуда: НН
Сообщений: 179
добавил
    if @rel_card <> 0

конечно же
8 дек 11, 17:58    [11731690]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
Glory
Member

Откуда:
Сообщений: 104751
gandalf-the-grey
EDatabaseError - Row cannot be located for updating. Some values may have been changed since it was last read

Так вот сопсно вопрос: почему при отсутствии условия в триггере (на insert причем, заметьте) все апдейтится, а при наличии - иксепшн?

Наверное потому, что ваш триггер уже поменял эту запись и теперь Row cannot be located for updating
Потому что Some values may have been changed since it was last read
8 дек 11, 18:01    [11731712]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
Glory
Member

Откуда:
Сообщений: 104751
И зачем в триггере курсор по inserted? Чтобы медленнее было ?
8 дек 11, 18:02    [11731718]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
gandalf-the-grey
Member

Откуда: НН
Сообщений: 179
Glory
Наверное потому, что ваш триггер уже поменял эту запись и теперь Row cannot be located for updating
Потому что Some values may have been changed since it was last read

это я и сам прекрасно понимаю. Вопрос вот в чом:
8 дек 11, 18:07    [11731758]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
gandalf-the-grey
Member

Откуда: НН
Сообщений: 179
разве раньше, пока доп. условия не было - триггер не менял запись?
8 дек 11, 18:09    [11731768]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
Glory
Member

Откуда:
Сообщений: 104751
gandalf-the-grey
разве раньше, пока доп. условия не было - триггер не менял запись?

Откуда же это известно ?
8 дек 11, 18:10    [11731783]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
gandalf-the-grey
Member

Откуда: НН
Сообщений: 179
Glory
gandalf-the-grey
разве раньше, пока доп. условия не было - триггер не менял запись?

Откуда же это известно ?

ну, мне доподлинно известно, бд уже не один год крутится.
если записи нет - она добавляется, если есть - она _безусловно_ апдейтится. А потом без Requery датасета ещё и апдейтится.
Доп условие добавил - чтобы не апдейтилось при 0 в изменяемом поле. Вот только тут ошибка и вылезла. Я её сопсно и исправил уже, но хочется понять поведение БД и ADO-компонентов.

Про курсор в триггере - ну, да, есть косяк, переписать этот проект руки не дошли.
8 дек 11, 18:16    [11731829]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
Glory
Member

Откуда:
Сообщений: 104751
gandalf-the-grey
ну, мне доподлинно известно, бд уже не один год крутится.

Что известно то ?
Вам же приложение ясно написало
По тем данным, что имеются у программы в ДатаСете она не может найти запись
8 дек 11, 18:18    [11731851]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
gandalf-the-grey
Member

Откуда: НН
Сообщений: 179
Glory
gandalf-the-grey
ну, мне доподлинно известно, бд уже не один год крутится.

Что известно то ?
Вам же приложение ясно написало
По тем данным, что имеются у программы в ДатаСете она не может найти запись

хорошо, приведу пример:
в датасет добавляются 2 записи:
cardstatusstatus_daterelated_card
63286911ACTIVE2011-11-03 11:31:17.0000
63286911RESTRICTED2011-10-29 11:46:31.0000


Делаем Post();
В таблице уже есть запси
cardstatusstatus_daterelated_card
63286911ACTIVE2011-11-03 11:31:17.00026226211
63286911RESTRICTED2011-10-29 11:46:31.0000

поэтому происходит апдейт поля related_card обеих строк по триггеру (условия то нет!)

затем в датасете меняется поле related_card первой строки, делаем Post, снова в таблице получаем
cardstatusstatus_daterelated_card
63286911ACTIVE2011-11-03 11:31:17.00026226211
63286911RESTRICTED2011-10-29 11:46:31.0000


Теперь добавим в триггер условие перед update CardEvent
if @rel_card <>0

воспроизведем последовательность

в датасет добавляются 2 записи:
cardstatusstatus_daterelated_card
63286911ACTIVE2011-11-03 11:31:17.0000
63286911RESTRICTED2011-10-29 11:46:31.0000


Делаем Post();
В таблице уже есть запси
cardstatusstatus_daterelated_card
63286911ACTIVE2011-11-03 11:31:17.00026226211
63286911RESTRICTED2011-10-29 11:46:31.0000

поэтому апдейт поля related_card обеих строк по триггеру НЕ ПРОИСХОДИТ, ибо related_card в обеих записях в датасете равен 0

затем в датасете меняется поле related_card первой строки, делаем Post, получаем иксепшн...
8 дек 11, 18:31    [11731950]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
Glory
Member

Откуда:
Сообщений: 104751
gandalf-the-grey
хорошо, приведу пример:
в датасет добавляются 2 записи:

Что вы мне то на пальцах объясняете
Объясните это своем ДатаСету - какие поля он должен использовать для поиска записей
Заодно узнайте, действительно ли по значениям, которые _есть в ДатаСете_ , можно найти какую то запись
8 дек 11, 18:34    [11731964]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
gandalf-the-grey
Member

Откуда: НН
Сообщений: 179
Glory,

кажется, я сам уже все понял... туплю...
8 дек 11, 18:38    [11731990]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
Glory
Member

Откуда:
Сообщений: 104751
gandalf-the-grey
кажется, я сам уже все понял... туплю...

ДатаСет хранит какие то значения. На основании которых он строит команды серверу
Иначе как бы он мог изменять конкретную запись ?
И если эту запись он найти не может, то значит в ДатаСете и базе данные различаются
8 дек 11, 18:42    [11732019]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
gandalf-the-grey
Member

Откуда: НН
Сообщений: 179
Glory,

ну, я в общем то, не совсем дурак))

при отсутствии условия в триггере записи безусловно апдейтятся при Посте датасета. При наличии условия в триггере апдейта реального не происходит. Просто не происходит никаких изменений данныхНо набор данных в обоих случая наличествует одинаковый и меняется одинаково в датасете.

в итоге я понимаю, как это исправить, но вот хоть убей не понимаю, почему датасет решает, что не может найти безусловно нужную строку в БД... исходные данные то одинаковы в обоих случаях. Есть три ключевых поля, по которым констрейт сделан в таблице. И четвертое - изменяемое. Ну не понимаю до конца... что-то крутится в голове, но не формализуется.
8 дек 11, 19:08    [11732131]     Ответить | Цитировать Сообщить модератору
 Re: Непонятный Exception при udate, помогите разобраться  [new]
Glory
Member

Откуда:
Сообщений: 104751
gandalf-the-grey
в итоге я понимаю, как это исправить, но вот хоть убей не понимаю, почему датасет решает, что не может найти безусловно нужную строку в БД... исходные данные то одинаковы в обоих случаях.

Повторяю вопрос - на основании каких значений ваш Датасет позиционирует записи ?
gandalf-the-grey
Есть три ключевых поля, по которым констрейт сделан в таблице. И четвертое - изменяемое.

Почему вы решили, что Датасет позиционирует записи по табличному констрейнту ?
8 дек 11, 19:14    [11732153]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить