Interbase trigers

19 отговора 309 прегледа
#1

Interbase trigers

Здравйте,

имам следния проблем : Работя с IBLocal server.
Създал cъм база данни с 4 таблици.
За една от таблиците съм създал генератор и тригер
тъй като има AutoIncrement поле:

CREATE GENERATOR REC_NO_GEN;

CREATE TRIGGER SET_REC_NO FOR STOCK
ACTIVE BEFORE INSERT POSITION 0 as
begin
new.ids = gen_id(rec_no_gen, 1);
end

Създал съм проект в чиято форма има DBGrid контрола
IBDatabase, IBTable, IBTransaktion i DataSourse.
DBGrid контролата естествено е свързана с IBTable чрез DataSourse. IBTablе->DataBaseName с IBDatabase
IBTable->Transaction с IBTransaction.
При въвеждане на данни в DBGrid-а, в полето ids което трябва да се пълни от тригера няма нищо , и естествено при съхранение на записа дава грешка.
Как мога да накарам тригера да заработи.

Отговор
в отговор на turtle #2

Re: Interbase trigers

Веднъж след backup i restore на базата ми се бяха деактивирали всички генератори /сигурно нещо съм експериментирал/. Ефектът беше същия - не се генерираше стойност за ключовото поле.

Отговор
в отговор на turtle #3

Re: Interbase trigers

1.Препоръчвам тригера да стане:
CREATE TRIGGER SET_REC_NO FOR STOCK
ACTIVE BEFORE INSERT POSITION 0 as
begin
If (new.ids is null) then
new.ids = gen_id(rec_no_gen, 1);
end

Така си "запазваш" правото да вмъкваш записи за които си генерирал id (напр. на клиента).
2. В този случай (а и в почти всички други) изхвърли IBTable. По-добре ползвай IBDataset, като съставиш съответните insert/update/delete/refresh изрази.

Отговор
в отговор на turtle #4

Re: Interbase trigers

Вероятно си си добавил филдовете на таблицата чрез fieldseditor, нали? Аз си мисля, че си си задал колоната ids да е not null в базата (предполагам, че все пак това ти е primary key-а ). Отвори си пак fields editor-а и на колоната ids й дай required да е false. това трябва да ти оправи нещата.
силно ти препоръчвам да не използваш Ibtable. той е оставен дет' се вика за съвместимост. използвай ibdataset или ibquery + ibupdatesql. а и така направено (чрез тригер) е малко неудобно за работа - не си знаеш id-тата на новите записи. защо не използваш generatorfield пропъртито на ibx-a? ама си ъпдейтни компонентите, щото тези дето идват с делфито са малко по-бъгави от последните им версии

Отговор
в отговор на turtle #5

Re: Interbase trigers

Ако ти дава грешка, че полето е празно - каквото си мисля, че е -
има и друг начин да се реши проблема - double click на компонента - IBTable или IBQuery - за да се отвори прозореца за редактиране на полетата. След което избираш полето което ти дава грешка - и търсиш property Required - или нещо такова - и го слагаш на False. При инициализация IBXxxxx гледа дефиницията на полето - ако първичен ключ или ако в базата данни е описано като required - сетва този флаг.
Това обаче е заобиколно решение - не за друго ами защото auto inc полетата ще бъдат обновени чак след приключване на транзакцията и няма да е хубаво да гледаш празни полета в грида нали - помисли какво точно искаш да постигнеш.

---
Е т'ва е живот!
Отговор
в отговор на PhantomAS #6

Re: Interbase trigers

Няма да е чак след приключването на транзакцията. Те ще са видими, защото тригера работи в същия контекст на транзакция, в който е и делфито. Проблема е, че за да ги види в програмата/грида, трябва да направи рефреш. А рефреш се прави по първичен ключ . Иначе трябва да си затвори/отвори таблицата, а тогава дет' се вика "а познай сега кой запис вкарах"

Отговор
в отговор на andrew_nikoloff #7

Re: Interbase trigers

Мддааа ама не - поне моите меща нещо не работят така - докато не се даде commit на транзакцията колкото и да рефрешваш - все остава тая - и това е нормално - помисли - имаш клиент - сървър. Първо insert се прави при клиента - и след като приключиш операцията по въвеждане на данните (не знам дали ще можеш да направиш смислен рефреш при положение че нямаш нищо въведено - не е задължително да е само първичен ключ) тогава се изпълнява insert на сървъра. Поиграх си да тествам с пълен дъмп на операциите - става дума за IBX компонентите - но не успях да го накарам да ми изпълни тригер преди реално да направиш insert от страна на сървъра - а до това (не знам защо ???!?!??) се стига след като дадеш commit - или нова операция за вмъкване. Явно нещо не правя както трябва - или не съм нагласил параметрите на транзакцията???
Разбира се при IBX може да се заобиколи това за едно поле - като се използват определени свойства на компоентите за връзка с генераторите, ама това е за едно поле - а пък аз искам да ползвам тригери и на вси4кото отгоре да ми се показват данните (става дума за стойости по подразбиране които се задават с default или с тригери). Елеметарно тъпия Парадокс го може - ама това е защото той не е сървърно ориентиран - нормално - при сървърите се цели снижаване на трафика и мрежовите операции все пак.
Друго глупаво нещо (което на мен не ми харесва ) е предаването на null ако не попълниш нищо в дадено поле - т.е. аз не искам да ми се insert-ват неща които не съм попълвал - ама не става - можеха да оправят компонентите поне да оптимизират това - ама не.

---
Е т'ва е живот!
Отговор
в отговор на andrew_nikoloff #8

Re: Interbase trigers

Проблема го реших чрез използване на IBDataSet и property-то му Generatorfield, като на Apply Event съм оставил OnServer.В SelectSQL съм задал "select ids, name, image from Stock" т.е. ids ми е primary key, name e char(30) a image e blob SUB_TYPE 0 SEGMENT SIZE 8 в него се съхраняват изображения.С тази заявка в грида ми се изобразява цялата таблица.Като използвам IBTable и се разхождам в грида по записите в DBImage се показва изображението за всеки запис.DBImage е свързано със полето image на таблицата.Как мога чрез IBDataSet да постигна същия резултат и стойноста на ключа генериран от генератора да се показва в грида веднага след постването на всеки запис в таблицата. А ето как се пълнят изображенията в таблицата:

void __fastcall TfrmMain::DBImageClick(TObject *Sender)
{
if(OpenPictureDialog1->Execute() == ID_OK)
{
if(IBDataSet->State == dsBrowse)
{
IBDataSet->Edit();
IBDataSetIMAGE->LoadFromFile(OpenPictureDialog1->FileName) ;
IBDataSet->Post();
DBImage->Picture->LoadFromFile(OpenPictureDialog1->FileName);
}
}
}

като на ModifaySQL съм задал следното: update Stock set image = :image.
Когато използвам IBTable няма проблем защото там има текущ запис и това изображение се пълни за него.Когато използвам IBDataSet аз получавам от заявката select един набор от данни но потдържа ли се текущ запис тъй като горния код се изпълнява без грешка но няма никакъв ефект .Като се разхождам по грида няма никакви изображения в DBImage(при използването на IBDataSet).
Искам да получа същия ефект като при използването на IBTable след като ме съветвате да не го използвам. Ще се радвам ако приложите код!

Отговор
в отговор на PhantomAS #9

Re: Interbase trigers

Реално insert-а на данните на сървъра не става при приключване на транзакцията, а при post на dataset-а ти. Провери ако не вярваш. И ти ще си виждаш данните които си постнал, но това при условие, че ги гледаш в контекста на същата транзакция. А иначе си погледни в API-то на InterBase-а за параметрите на транзакциите. Много неща зависят от тях. Дъмп-а с какво го правиш? IBSQLMonitor? Сигурен ли си, че тригера не ти се е изпълнил а не е било ти да не можеш да го видиш, защото си бил в друга транзакция? (Мен ако питаш май точно това е било...) А по въпроса за рефреша - естествено че може и да не е по първичен ключ, ама практически основно е по него.

Отговор
в отговор на turtle #10

Re: Interbase trigers

Zdrasti.
Az izpolzwam slednata tehnika.
Wmesto triger si syzdawam zapazena procedura. n.r.

CREATE PROCEDURE GET_U_OBJECT_ID RETURNS (
NEW_VALUE INTEGER
) AS
BEGIN
NEW_VALUE=GEN_ID(OBJECT_ID_GEN,1);
SUSPEND;
END

Seld towa na sybitieto beforepost na tablicata priwoiawash na poleto s
pyrwichniat kliuch wryshtanata stoinost ot procedurata

procedure TDM.tbObjectBeforePost(DataSet: TDataSet);
begin
if DataSet.State = dsInsert then begin
spNewObjectID.Prepare;
try
spNewObjectID.ExecProc;
tbObjectOBJECT_ID.Value:=spNewObjectID.Params[0].Value;
finally
spNewObjectID.UnPrepare;
end;
end;
end;

Ne sam siguren dali shte stane s IB componentite zashtoto az sam go probwal
samo s obiknowenite DataBase komponenti (Delphi 5)

Отговор
в отговор на tpt #11

Re: Interbase trigers

Ще стане. Не е проблем. Ама ако ще го правиш така няма смисъл от сторедпроцедурата. Сложи си едно IBQuery или IBSQL и за SelectSQL-а напиши

Select Gen_ID(MY_GENERATOR, 1) from RDB$DATABASE

и тогава на AfterInsert (ако го сложиш там си спестяваш проверката на BeforePost) пишеш

procedure TForm1.tbMyTableAfterInsert(Sender: TObject);
begin
qID.ExecSQL; //или qID.Open;
try
tbMyTableID.AsInteger := qID.Fields[0].AsInteger;
finally
qID.Close;
end;
end;

Отговор
в отговор на andrew_nikoloff #12

Re: Interbase trigers

Wsichko towa e mnogo hubawo, obache kak shte naprawish Insert ako ne si zadal stoinost na pyrwichniat kluch(a i niamame triger)?

Отговор
в отговор на tpt #13

Re: Interbase trigers

AfterInsert на DataSet-а се вика след като таблицата ти влезе в режим dsInsert. Не го бъркай с AfterInsert като тригер.

Отговор
в отговор на tpt #15

Re: Interbase trigers

Kato zabelejka.
Tai kato pri wseki Insert shte se uvelicahwa generatora, ima weroiatnost nomerata da ne warwiat posledowatelno.
N.r.
Natiska buton now zapis ->generatora se uvelichawa, sled towa natiska buton Cancel.
Togawa nomeryt na seldwashtiat dobawen zapis shte byde s 2 po goliam ot predishniat.
Ne che e problem no e dosadno.

Отговор
в отговор на tpt #16

Re: Interbase trigers

Да, така е. Ако е въпроса за генериране на стойностите за първичния ключ това не е от значение. Най-добре си ползвай GeneratorField пропъртито, като му сложиш да си взима стойността на On Post.

Отговор
в отговор на andrew_nikoloff #17

Re: Interbase trigers

А как стои въпроса с изображенията които ти описах по-горе?

Отговор
в отговор на andrew_nikoloff #18

Re: Interbase trigers

Като му сложа OnPost генерира стойности през 2.Защо става така?Не може ли да генерира поредни стойности?
Можеш ли да ми изпратиш (ако имаш) някой пример който използва API функциите на Interbase? Ще ми е от голяма полза. И как мога да направя мониторинг на връзката между клиента и сървара.С SQL Monitor става ли след като не се използва BDE?

Отговор
в отговор на turtle #19

Re: Interbase trigers

Ами генерира ти през 2 (или може би имаш предвид през 1) защото ти се вика няколко пъти. Виж дали имаш тригер, който ти взима стойности от генератора, дали си махнал онова не BeforePost и т.н.
С API ще стане трудно, а и няма да спечелиш нищо. В момента нямам време да го направя.
Мониторинга си го направи с TIBSQLMonitor, а не TSQLMonitor. Той е същия, ама е за IBX.

Отговор
в отговор на turtle #20

Re: Interbase trigers

Ами вероятно нещо е имало с BLOB-овете. Така не мога да кажа нищо. Ако се сетя ще ти драсна едно примерче, хем аз да видя какъв е бил проблема...

П.П. Пробвах го - бачка си ок. Ако искаш дай емайл и ще ти пратя сорса и програмката

Редактирано от andrew_nikoloff на

Отговор