Модераторы: Akella

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Изменение значения генератора, FireBird+FIBPlus 
:(
    Опции темы
former
Дата 13.7.2009, 21:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


MEMS Expert
***


Профиль
Группа: Завсегдатай
Сообщений: 1166
Регистрация: 1.3.2006
Где: Россия

Репутация: 1
Всего: 17



Master-detail.
В триггере BeforeInsert master-таблицы выполняется проверка данных и, в случае ошибки, вызывается исключение. 
Изначально генерацию первичного ключа выполнял в триггере после всех проверок, однако потребовалось получать id добавленной записи для detale-таблицы и обновлять только измененную запись. Стал использовать AutoUpdateOptions компонента FIBDataSet master-таблицы. Но в этом случае генератор изменяется до проверки исключений в триггере. Получается, что если несколько раз возникало исключение, то номер записи будет больше на число исключений. 
Как избежать многократного изменения значения генератора, но при этом сохранить возможность получения ключа для detail-таблицы и обновления добавленной записи?
Active - false/true не предлагать.


--------------------
Достаточно снизить уровень мышления, чтобы иные почувствовали почву под ногами.
PM MAIL   Вверх
aryab
Дата 21.7.2009, 09:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 2
Регистрация: 21.7.2009

Репутация: 1
Всего: 1



Для FireBird 2.0 и больше

Код

insert into Table (...) 
values(...)
RETURNING Id;


после Post  поле id добавленной записи будет заполнено значением заполненным в базе
PM MAIL WWW Jabber   Вверх
Deniz
Дата 8.9.2009, 07:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1251
Регистрация: 16.10.2004
Где: Новый Уренгой

Репутация: 22
Всего: 44



former, вопрос еще актуален?


--------------------
"Для того чтобы сделать шаг вперед, достаточно пинка сзади" (с)
PM ICQ   Вверх
former
Дата 8.9.2009, 08:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


MEMS Expert
***


Профиль
Группа: Завсегдатай
Сообщений: 1166
Регистрация: 1.3.2006
Где: Россия

Репутация: 1
Всего: 17



Deniz, если есть еще вариатны, с удовольствием их выслушаю.


--------------------
Достаточно снизить уровень мышления, чтобы иные почувствовали почву под ногами.
PM MAIL   Вверх
Akella
Дата 8.9.2009, 09:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



former, я вообще не понимаю, зачем так делать, что вызов исключения влияет на срабатывание генератора?
Ты хоть бы код показал
PM MAIL   Вверх
former
Дата 8.9.2009, 09:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


MEMS Expert
***


Профиль
Группа: Завсегдатай
Сообщений: 1166
Регистрация: 1.3.2006
Где: Россия

Репутация: 1
Всего: 17



Цитата(Akella @  8.9.2009,  09:20 Найти цитируемый пост)
former, я вообще не понимаю, зачем так делать, что вызов исключения влияет на срабатывание генератора?

Именно. В AutoUpdateOptions есть свойство WhenGetGenID, которое имеет wgNever (не используется), wgBeforePost (перед вызовом Post), wgOnNewRecord (при вызове Insert). 
У меня контроль данных осуществляется в триггерах с вызовом исключений. Получается следующее:
wgOnNewRecord
Вызываем Insert, генерируется значение ключа, вводим данные, вызываем Post, получаем исключение, а генератор уже изменен.
wgBeforePost
Вызываем Insert, вводим данные, вызываем Post (генерируется значение ключа), получаем исключение, а генератор уже изменен.
А для выполнения Refresh необходимо значение ключа добавленной записи.
Цитата(Akella @  8.9.2009,  09:20 Найти цитируемый пост)
Ты хоть бы код показал 

ИХМО:А код тут не причем.


--------------------
Достаточно снизить уровень мышления, чтобы иные почувствовали почву под ногами.
PM MAIL   Вверх
Akella
Дата 8.9.2009, 10:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



у компоненты базы данных (FibDataBase) есть метод получения кода генератора, его и используй. В этом случае триггер не будешь трогать.

Добавлено через 2 минуты и 33 секунды
Пример
Код

  table1.Insert;
  table1.FBN('ID') :=  dbScanFilter.Gen_Id('my_super_generator', 1, dbScanFilter.DefaultTransaction);
  table1.FBN('Akella') := 'CyberWolf';
  table1.post;


Добавлено через 4 минуты и 15 секунд
Цитата(former @  8.9.2009,  09:43 Найти цитируемый пост)
ИХМО:А код тут не причем. 

а ты поставь код получения значения генератора после кода вызова исключения smile 
тогда в случае исключения код получения значения генератора не будет срабатывать smile
PM MAIL   Вверх
former
Дата 8.9.2009, 10:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


MEMS Expert
***


Профиль
Группа: Завсегдатай
Сообщений: 1166
Регистрация: 1.3.2006
Где: Россия

Репутация: 1
Всего: 17



Цитата(Akella @  8.9.2009,  10:31 Найти цитируемый пост)
у компоненты базы данных (FibDataBase) есть метод получения кода генератора, его и используй. В этом случае триггер не будешь трогать.

В твоем коде, в случае возникновения исключения и повторного вызова метода Post, будет сгенерировано новое значение генератора. А если возникнет несколько исключений, то вместо 15-го мы запишем запись с ключем номер 25. Не очень хочется "транжирить" генератор.
Цитата(Akella @  8.9.2009,  10:31 Найти цитируемый пост)
а ты поставь код получения значения генератора после кода вызова исключения smile 
тогда в случае исключения код получения значения генератора не будет срабатывать smile 

Именно так я и делаю:
Код

CREATE OR ALTER TRIGGER COURSES_BI FOR COURSES
ACTIVE BEFORE INSERT POSITION 0
AS
begin
  if (new.coursename is null or  new.coursename = '') then exception courses_coursename_null;
  else if (new.hours is null or new.hours = '') then exception courses_hours_null;
  else if (exists(select * from courses where (coursename = new.coursename) and
           (hours = new.hours) and (departmentid = new.departmentid))) then
    exception courses_duplicate;
  else if (new.courseid is null) then
    new.courseid = gen_id(gen_courses_id,1);
end
^

Akella, для Refresh тогда откуда возьмется ключ записи? 

Это сообщение отредактировал(а) former - 8.9.2009, 10:51


--------------------
Достаточно снизить уровень мышления, чтобы иные почувствовали почву под ногами.
PM MAIL   Вверх
Akella
Дата 8.9.2009, 11:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



Цитата(former @  8.9.2009,  10:49 Найти цитируемый пост)
Akella, для Refresh тогда откуда возьмется ключ записи? 

А при чём здесь генератор?
PM MAIL   Вверх
former
Дата 8.9.2009, 11:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


MEMS Expert
***


Профиль
Группа: Завсегдатай
Сообщений: 1166
Регистрация: 1.3.2006
Где: Россия

Репутация: 1
Всего: 17



Цитата(Akella @  8.9.2009,  11:17 Найти цитируемый пост)
А при чём здесь генератор? 

А вот причем:
Код

SELECT
    C.COURSEID,
    C.COURSENAME,
    C.HOURS,
    C.DEPARTMENTID,
    D.SDEPNAME,
    C.CSACTUALITY
FROM COURSES  AS C
    INNER JOIN DEPARTMENTS AS D
      ON D.DEPARTMENTID = C.DEPARTMENTID
WHERE C.COURSEID = :OLD_COURSEID

Обрати внимание на последнюю строку.


--------------------
Достаточно снизить уровень мышления, чтобы иные почувствовали почву под ногами.
PM MAIL   Вверх
Akella
Дата 8.9.2009, 12:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



Refresh выполняется после чего? После Update!
абчём говорит эта строка?
Код

WHERE C.COURSEID = :OLD_COURSEID


Добавлено через 1 минуту и 1 секунду
Если речь идёт об insert, то нужн что делать? Правильно - pFibDataSet1.CloseOpen();
PM MAIL   Вверх
Deniz
Дата 8.9.2009, 13:04 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1251
Регистрация: 16.10.2004
Где: Новый Уренгой

Репутация: 22
Всего: 44



Цитата(former @  8.9.2009,  13:49 Найти цитируемый пост)
Не очень хочется "транжирить" генератор.
Вот с этого все и начинается  smile
Попробуй посчитать сколько примерно сотен лет нужно чтобы занять весь генератор при условии что 1 запись вставляется каждую секунду в режиме 24х7.
Далее, не совсем понятно почему часть бизнес логики (по обработке 1 записи) вынесена в триггер, а часть остается на клиенте.
Далее, такие проверки как в триггере, можно оформить как not null на поле, а на клиенте преобразовывать пустые в null (есть вроде такая опция в FIBPlus)
Далее, удивил код с 
Код
exception courses_duplicate;
это реальные грабли, причем получишь ими, когда люди начнут работать толпой, лучше пользуй уникальные индексы.
И наконец, если мне не изменяет память, то после исключения на POST, DataSet остается в режиме редактирования, и повторно onNewRecord не вызывается, если только ты сам не делаешь Cancel.


--------------------
"Для того чтобы сделать шаг вперед, достаточно пинка сзади" (с)
PM ICQ   Вверх
former
Дата 8.9.2009, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


MEMS Expert
***


Профиль
Группа: Завсегдатай
Сообщений: 1166
Регистрация: 1.3.2006
Где: Россия

Репутация: 1
Всего: 17



Цитата(Deniz @  8.9.2009,  13:04 Найти цитируемый пост)
Попробуй посчитать сколько примерно сотен лет нужно чтобы занять весь генератор при условии что 1 запись вставляется каждую секунду в режиме 24х7.

Порядка 30 млн. записей в год. В некоторых случаях мне нужна четкая последовательность нумерации.
Цитата(Deniz @  8.9.2009,  13:04 Найти цитируемый пост)
Далее, не совсем понятно почему часть бизнес логики (по обработке 1 записи) вынесена в триггер, а часть остается на клиенте.
Далее, такие проверки как в триггере, можно оформить как not null на поле, а на клиенте преобразовывать пустые в null (есть вроде такая опция в FIBPlus)

Где такое написано, что преобразование идет на клиенте? Клиент только передает данные.
Цитата(Deniz @  8.9.2009,  13:04 Найти цитируемый пост)
это реальные грабли, причем получишь ими, когда люди начнут работать толпой, лучше пользуй уникальные индексы.
И наконец, если мне не изменяет память, то после исключения на POST, DataSet остается в режиме редактирования, и повторно onNewRecord не вызывается, если только ты сам не делаешь Cancel. 

Цитата(Deniz @  8.9.2009,  13:04 Найти цитируемый пост)
это реальные грабли, причем получишь ими, когда люди начнут работать толпой, лучше пользуй уникальные индексы.

Это если уникальность в одном поле. А когда уникальность по нескольким полям то как?
Какие грабли?
Цитата(Deniz @  8.9.2009,  13:04 Найти цитируемый пост)
И наконец, если мне не изменяет память, то после исключения на POST, DataSet остается в режиме редактирования, и повторно onNewRecord не вызывается, если только ты сам не делаешь Cancel. 

Да, именно если пользователь делает Cancel.

Это сообщение отредактировал(а) former - 8.9.2009, 14:04


--------------------
Достаточно снизить уровень мышления, чтобы иные почувствовали почву под ногами.
PM MAIL   Вверх
former
Дата 8.9.2009, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


MEMS Expert
***


Профиль
Группа: Завсегдатай
Сообщений: 1166
Регистрация: 1.3.2006
Где: Россия

Репутация: 1
Всего: 17



Цитата(Akella @  8.9.2009,  12:50 Найти цитируемый пост)
Refresh выполняется после чего? После Update!
абчём говорит эта строка?

В опциях стоит RefreshAfterPost:=true. Если установлено свойство WhenGetGenID в wgBeforePost или wgOnNewRecord, Id для обновления берется из него.
А если wgNever, то можно подсунуть Refresh-у номер записи и он ее обновит.
Цитата(Akella @  8.9.2009,  12:50 Найти цитируемый пост)
Если речь идёт об insert, то нужн что делать? Правильно - pFibDataSet1.CloseOpen(); 

Если делать pFibDataSet1.CloseOpen(), то потом нужно будет искать добавленную запись. А так, сразу попадаем на нужную запись. Тем более весь набор данных заново открывать.

Это сообщение отредактировал(а) former - 8.9.2009, 14:22


--------------------
Достаточно снизить уровень мышления, чтобы иные почувствовали почву под ногами.
PM MAIL   Вверх
Deniz
Дата 8.9.2009, 14:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1251
Регистрация: 16.10.2004
Где: Новый Уренгой

Репутация: 22
Всего: 44



Цитата(former @  8.9.2009,  17:02 Найти цитируемый пост)
Порядка 30 млн. записей в год.
это твой реальный прирост?

Цитата(former @  8.9.2009,  17:02 Найти цитируемый пост)
В некоторых случаях мне нужна четкая последовательность нумерации.
зачем? Поподробнее можно? Обычно id кроме разработчиков никто не видит.

Цитата(former @  8.9.2009,  17:02 Найти цитируемый пост)
Это если уникальность в одном поле. А когда уникальность по нескольким полям то как?
а что уникальные составные ключи отменили? Из Firebird-2.0-LangRef:
Код
CREATE [UNIQUE] [ASC[ENDING] | [DESC[ENDING]] INDEX indexname
ON tablename
{ (colname [, colname ...]) | COMPUTED BY (expression) }


Цитата(former @  8.9.2009,  17:02 Найти цитируемый пост)
Какие грабли?
Запрос 
Код
if (exists(select * from courses ...) then exception courses_duplicate;
работает в контексте транзакции, т.е. на момент запроса в базе уже может быть такая запись, в неподтвержденной транзакции, и твой запрос ее не увидит, а потом транзакция подтвердится и ты получишь 2 одинаковые записи.

Если уж так необходимо гарантировано соблюсти последовательность, то оформить insert into в хранимку с предварительной проверкой и последующей вставкой. Результат храминки или ID или код ошибки (например отрицательный).



--------------------
"Для того чтобы сделать шаг вперед, достаточно пинка сзади" (с)
PM ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Interbase"
Alex

Обязательно указание:

1. Версию InterBase (Firebird, Yaffil)

2. Способа доступа (ADO, BDE, IBX и т.д.)

  • КАК ПРАВИЛЬНО ОФОРМИТЬ КОД - ЗДЕСЬ
  • КАК ПРАВИЛЬНО УКАЗАТЬ ТЕКСТ ОШИБКИ - ЗДЕСЬ
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • FAQ раздела лежит здесь!

Если Вам понравилась атмосфера форума, заходите к нам чаще! С Уважением, Akella.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Firebird, Interbase | Следующая тема »


 




[ Время генерации скрипта: 0.1151 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.