C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Помогите найти "плюшку"
oev
Отправлено: 09.12.2003, 13:48


Ученик-кочегар

Группа: Участник
Сообщений: 11



Очень прошу, помогите!!!!

Есть форма с гридом, в котором отображаются записи из запроса Q, и с кнопкой "Добавить".
Добавляю новую запись (т.е. нажимаю на кнопку "Добавить", открывается форма с пустыми реквизитами, заполняю ее и нажимаю на кнопку "Сохранить", где происходит UpdateBatch запроса Q).
При этом (при выполнении строки программы
Q->UpdateBatch(arCurrent) ) выдается ошибка:
'Row handle referred to a deleted row marked for deletion'.
После чего запись успешно добавляется, но курсор стоит не на добавленной записи, а на первой (в гриде).
Хотелось бы узнать: как устранить эту ошибку и поставить курсор на добавленную, а не на первую запись в гриде (запрос Q имеет сортировку, поэтому вновь добавленная запись может оказаться не в конце, а где-нибудь в середине грида).
Nick
Отправлено: 09.12.2003, 14:18


Машинист паровоза

Группа: Участник
Сообщений: 247



На форме бланке поля записывают данные вбазу или это просто
TEdit ???

Q->Insert();
// заполнение полей
Q->Post(); // курсор должен остаться на добавленной записи

oev
Отправлено: 10.12.2003, 08:46


Ученик-кочегар

Группа: Участник
Сообщений: 11



Спасибо за совет, но, к сожалению, он не совсем мне подходит.
Если писать Q->Post(), то добавленной записи не присваивается значение ключевого поля ID, а я ради его все и делаю, т.к. мне этот ID надо передать параметром в другой запрос.
Еще нюанс: этот Q имеет DataSource. Перед добавлением записи я его, естественно обнуляю, а когда после Post(), присваиваю снова, курсор уходит с добавленной записи.
Nick
Отправлено: 10.12.2003, 08:59


Машинист паровоза

Группа: Участник
Сообщений: 247



Что-то непонятно ты с какими БД работаешь ???
oev
Отправлено: 10.12.2003, 09:28


Ученик-кочегар

Группа: Участник
Сообщений: 11



с dbo. (SQL Server)

Отредактировано oev — 10/12/2003, 10:45
Nick
Отправлено: 10.12.2003, 12:50


Машинист паровоза

Группа: Участник
Сообщений: 247



Ну тогда наверно не смогу помочь.
Работаю с IBase.
ID заполняю или с помощью генератора
или процедурой.
DataSet не очищаю, даже не слышал об таком.
oev
Отправлено: 10.12.2003, 13:26


Ученик-кочегар

Группа: Участник
Сообщений: 11



Спасибо и на этом.
Может быть еще кто-нибудь откликнется и сможет помочь?
Я очень нуждаюсь в помощи. SOS!!!!
Monster
Отправлено: 10.12.2003, 14:30


Ученик-кочегар

Группа: Участник
Сообщений: 10



Попробую.
Напиши подробнее задачу:
Какие компоненты используешь (ADO, BDE) ?
Q — что это за компонент?
Что за ключевое поле Id? Idenitity?
Подробнее опиши механизм работы, я не понял, почему тебе не подходит Post() ?
oev
Отправлено: 10.12.2003, 15:20


Ученик-кочегар

Группа: Участник
Сообщений: 11



Использую ADO.
Q — это компонент TAQuery.
Поле ID — это Identity.
Есть форма с гридом и разными кнопками, из которых меня сейчас интересует "Добавить".
При нажатии на нее делается Q->Append() и открывается другая форма (с пустыми TDBEdit и др. компонентами), в которой заполняю данные для добавляемой строки. На этой ("второй") форме есть кнопка, при нажатии на которую должна открыться третья форма, отображающая данные из др.запроса (Q2). Этот Q2 — с параметром, значение которого — ID из запроса Q. Поэтому мне надо, чтобы этот ID был заполнен (а это происходит при апдейте запроса) и чтобы "курсор" был на этой строке (чтобы правильно передать параметр). Запрос Q отсортирован по др. полю (не по ID), поэтому после апдейта добавленная запись может оказаться где-нибудь в середине грида (который на первой форме), т.е. она не является первой или последнейзаписью в запросе Q.
На тадлицу (T1), на которой построен запрос Q, есть триггер на Insert, в котором добавляется запись в таблицу T2 (на которой построен запрос Q2).
Еще проблема в том, что почему-то при апдейте запроса Q выдается ошибка(см. первое мое сообщение).
(Добавляла запись в T1 напрямую через Enterpris Meneger — триггер работает правильно и никаких ошибок не выдается).
Если в триггере закоментирую строчку "Inset into T2...", то при добавлении записи через программу ошибка не выдается.
Я так и не могу понять, влияет ли эта ошибка на положение курсора в Q (и в гриде) или нет, но так и не могу ни устранить ее, ни добиться того, чтобы Q2 открывался с нужными параметрами (т.е. чтобы был ID в Q и курсор оставался на этой строке)
Написала много и запутанно, т.к. мучаюсь с этим уже неделю и голова идет кругом.
Monster
Отправлено: 10.12.2003, 15:52


Ученик-кочегар

Группа: Участник
Сообщений: 10



Может не совсем точно, но примерно понял твою заморочку.
Чтобы понять досконально, надо смотреть все твое хозяйство, а у меня никакой тяги к этому нет.

Лучше просто напишу, как я делаю в таких ситуациях:
1. Никаких добавлений в другие таблицы (Т2) через триггеры. Это чревато тем, что через пару-тройку месяцев ты об этом забудешь и в работе программы начнуться странности.
2. Если ты работаешь через ADO, то в нем значение Identity проставляется автоматически после Post.
3. Кнопку на открытие второй формы надо запретить до сохранения данных первой формы. Чаще всего такой простой вариант устраивает пользователей. Если нет — напиши, предложу другие, но более сложные.
4. Далее — все просто: отредактировала Т1, сделала Post(), разрешила кнопку на открытие второй формы, получила значение Id, передала его во вторую форму.

Если твоя проблема именно в том, что при добавлении в Т1 запись в Т2 должна добавляться ОБЯЗАТЕЛЬНО через триггер, то опиши подробнее свою задачу. Уверен, можно найти способ обойтись без этого, попробую подсказать.
oev
Отправлено: 11.12.2003, 09:56


Ученик-кочегар

Группа: Участник
Сообщений: 11



Мне как раз и надо, чтобы все действия с таблицами были отражены в этой T2, в которую делаю insert через триггер. Отказаться от этого я не могу, наоборот — это очень удобно, и для других таблиц все работает нормально.
Все остальное я, в принципе, так и делаю, как Вы написали:
только я не запрещаю нажатие на кнопку открытия второй формы, а в обработчике события нажатия на эту кнопку сначала делаю Post, а потом открываю запрос с параметрами для второй формы и потом саму вторую форму (в принципе — все тоже самое, что Вы и советуете).
Проблема в том, что при Post() тоже выдается та же ошибка (если в триггере раскомментирован insert), после чего я в запросе не вижу этой добавленной записи, пока не присвою запросу Q DataSource и MasterFields (т.к. перед Append() их приходится отключать) и курсор никак не фиксируется на добавленной записи.
Monster
Отправлено: 11.12.2003, 10:14


Ученик-кочегар

Группа: Участник
Сообщений: 10



Доп. вопросы:
1. Какая версия SQL-Server? Какой на ней установлен Service Pack? (Это можно узнать через SELECT @@Version)
2. Имеются ли в таблице Т2 (куда триггер делает Insert) поле Identity?
3. В какой стране ты находишься? (Это к проблеме не относится).
Nick
Отправлено: 11.12.2003, 12:36


Машинист паровоза

Группа: Участник
Сообщений: 247



Если у Q и Q2 разные транзакции и ID Table2 уникален
Получается при добавлении Table1 в добавляется запись в Table2
в одной транзакции.
Другая транзакция для Q2 эту запись не увидит пока не будет
Commit (CommitRetaining) первой транзакции.
Возможно при открытии второй формы ты проверяешь и при необходимости добавляешь запись.
При сохранении и подтверждении обоих транзакций
возникнет конфликт т.к. я предположил что ID в Table2 уникален.

Фу, все это построено на предположениях, но все равно попробуй
Q и Q2 сделать в одной транзакции (если конечно они в разных).
oev
Отправлено: 15.12.2003, 06:23


Ученик-кочегар

Группа: Участник
Сообщений: 11



Microsoft SQL Server 2000
Service Pack 3
В T2 поле identity конечно есть.
Я из России.
Monster
Отправлено: 15.12.2003, 10:40


Ученик-кочегар

Группа: Участник
Сообщений: 10



Тогда сделай вот что:
В триггере, который пишет в таблицу T2, первой строкой поставь команду:

SET NOCOUNT ON

Дело в том, что при срабатывании триггера, если ты в нем делаешь INSERT, SQL-Server возвращает клиенту строку "N rows affected", которая неверно интерпретируется ADO.
Напиши о результате.
Успеха!
oev
Отправлено: 16.12.2003, 06:13


Ученик-кочегар

Группа: Участник
Сообщений: 11



Это сделано изначально (я об этом знаю). — это на счет "set nocount on".

На счет транзакций — пыталась разобраться — вроде все нормально, но толком не могу понять: что именно надо проверять (как проверить — в одной они транзакции или нет).
Nick
Отправлено: 16.12.2003, 09:36


Машинист паровоза

Группа: Участник
Сообщений: 247



Простите я не посмотрел.
В ADO нет транзакций (отдельных компонентов).
В IB каждому DataSet присоед Компонент Transaction с любыми настройками.
У меня была примерно такая ситуация ...
Monster
Отправлено: 16.12.2003, 10:09


Ученик-кочегар

Группа: Участник
Сообщений: 10



Опубликуй полный скрипт на таблицы Т1 и Т2, включая индексы, check-и, foreign keys, и триггеры. Я попытаюсь разобраться.
oev
Отправлено: 16.12.2003, 13:00


Ученик-кочегар

Группа: Участник
Сообщений: 11



T1 такова:
CREATE TABLE [FU_VEKS_MOVE] (
[ID] [int] IDENTITY (1, 1) NOT NULL ,
[KD] [int] NULL ,
[KG_KTO] [int] NOT NULL ,
[KG_KOMU] [int] NOT NULL ,
[OPER] [int] NOT NULL ,
[DATAP] [datetime] NOT NULL ,
[MESTOP] [varchar] (20) COLLATE SQL_Latin1_General_CP1251_CI_AS NULL ,
[KOPL] [tinyint] NULL ,
[SUMMAP] [numeric](17, 2) NULL ,
[USLPL] [tinyint] NULL ,
[K_SH] [int] NULL ,
[AD] [tinyint] NULL ,
[PN] [int] NULL ,
[NI] [tinyint] NULL ,
[DIZM] [datetime] NULL ,
[OTM] [bit] NULL ,
[PNF] [int] NULL ,
[PPRV] [bit] NULL ,
[PNB] [int] NULL ,
[MES] [tinyint] NULL ,
[GOD] [int] NULL ,
[ZM] [bit] NULL ,
[CONTRACT_ID] [int] NULL ,
[KBE] [int] NULL ,
[DATA_BU] [datetime] NULL ,
[COMM_VIDD] [varchar] (45) COLLATE SQL_Latin1_General_CP1251_CI_AS NULL ,
[KD_VIDD] [int] NULL ,
[NZP] [int] NULL ,
CONSTRAINT [PK_FU_VEKS_MOVE] PRIMARY KEY CLUSTERED
(
[ID]
) WITH FILLFACTOR = 90 ON [PRIMARY] ,
CONSTRAINT [FK_FU_VEKS_MOVE_FU_VEKSEL] FOREIGN KEY
(
[KD]
) REFERENCES [FU_VEKSEL] (
[KD]
) ON DELETE CASCADE ON UPDATE CASCADE
) ON [PRIMARY]
GO

T2 такая:
CREATE TABLE [GB_GHO] (
[ID_HO] [int] IDENTITY (1, 1) NOT NULL ,
[KHO] [tinyint] NULL ,
[KVD] [tinyint] NULL ,
[KD] [int] NULL ,
[DATA_BU] [datetime] NULL ,
[S_BU] [numeric](19, 2) NULL ,
[K_VP] [int] NULL ,
[K_DBS] [int] NULL ,
[DBS] [varchar] (12) COLLATE SQL_Latin1_General_CP1251_CI_AS NULL ,
[K_KBS] [int] NULL ,
[KBS] [varchar] (12) COLLATE SQL_Latin1_General_CP1251_CI_AS NULL CONSTRAINT [DF__GB_GHO__KBS__5716FD90] DEFAULT (null),
[NN] [int] NULL ,
[KLV] [money] NULL ,
[DATA_PART] [datetime] NULL ,
[KVD_D] [tinyint] NULL ,
[KD_D] [int] NULL ,
[NZP_D] [tinyint] NULL ,
[KG_D] [int] NULL ,
[PN_D] [int] NULL ,
[KAU_D] [int] NULL ,
[KVD_K] [tinyint] NULL ,
[KD_K] [int] NULL ,
[NZP_K] [tinyint] NULL ,
[KG_K] [int] NULL ,
[PN_K] [int] NULL ,
[KAU_K] [int] NULL ,
[KAU_DOP] [bit] NULL ,
[MES] [smallint] NULL ,
[GOD] [smallint] NULL ,
[DATA_FU] [datetime] NULL ,
[S_FU] [money] NULL ,
[PN] [int] NULL ,
[DIZM] [datetime] NULL ,
[NI] [tinyint] NULL ,
[PN_B] [int] NULL ,
[KVD_OU] [tinyint] NULL ,
[KD_OU] [int] NULL ,
[DATA_OU] [datetime] NULL ,
[S_OU] [numeric](19, 2) NULL ,
[KBE] [int] NULL ,
[IMP_KRED] [datetime] NULL ,
[IMP_DEB] [datetime] NULL ,
[kgs_d] [int] NULL ,
[kgs_k] [int] NULL ,
CONSTRAINT [PK__GB_GHO__580B21C9] PRIMARY KEY CLUSTERED
(
[ID_HO]
) WITH FILLFACTOR = 90 ON [PRIMARY]
) ON [PRIMARY]
GO


Я закомментировала все триггеры на этих таблицах и создала на T1 пробный новый :
CREATE TRIGGER tr_move ON dbo.FU_VEKS_MOVE
FOR INSERT
AS

BEGIN
set nocount oт
INSERT INTO GB_GHO (kvd)
VALUES (38)
set nocount off
END

И все равно выдается эта несчастная ошибка, которая все портит.
Monster
Отправлено: 16.12.2003, 15:23


Ученик-кочегар

Группа: Участник
Сообщений: 10



Прежде всего мелкие замечания, к делу не относящиеся:
1. BEGIN и END в триггере не обязательны.
2. SET NOCOUNT OFF в конце тоже не обязательно.

Теперь о проблеме:
При срабатывании триггера на Т1 (то бишь на FU_VEKS_MOVE) и вставке в таблицу Т2 (то бишь в GB_GHO) изменяется системная переменная @@IDENTITY, т.е, до команды
INSERT INTO GB_GHO (kvd) VALUES (38)
она была равна значению поля FU_VEKS_MOVE.ID, то после этой команды она будет равна значению поля GB_GHO.ID_HO, которое естественно, другое. ADO проверяет значение именно этой переменной. Поэтому у тебя есть три варианта:
1. Отказаться от вставки в триггере.
2. Отказаться от IDENTITY (т.е сделать поле просто INT) в таблице GB_GHO.
3. Принудительно присвоить значение @@IDENTITY. Этот способ расточительный и кривой, я тебе его очень НЕ рекомендую.
oev
Отправлено: 17.12.2003, 06:57


Ученик-кочегар

Группа: Участник
Сообщений: 11



Большое спасибо за разъяснения.
Придется, наверное, отказаться от вставки в триггере, хотя очень не хочется.
Еще раз спасибо.

Вернуться в Работа с базами данных в C++Builder