Changes between Version 1 and Version 2 of DatabaseProgramming


Ignore:
Timestamp:
05/26/26 15:01:09 (27 hours ago)
Author:
231511
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • DatabaseProgramming

    v1 v2  
    2712717. **Заклучок:** 
    272272`catalog_object` претставува централен механизам за каталогизација во системот, кој обезбедува конзистентност, автоматизација и намалување на човечки грешки при внес на археолошки податоци.
     273
     274= Тригери =
     275
     276
     277=== Тригер 1: Валидација на хиерархија на фрагменти (trg_fragment_check) ===
     278
     2791. **Намена:** 
     280Тригерот `trg_fragment_check` е наменет за автоматска валидација на записите во табелата `Fragments`. Неговата главна цел е да спречи внесување или ажурирање на фрагмент кој истовремено е директно поврзан со археолошки предмет (`object_id`) и со друг фрагмент (`parent_fragment_id`).
     281
     2822. **Случај на употреба:** 
     283Во системот за управување со културно-археолошко наследство, фрагментите имаат важна улога затоа што претставуваат делови од артефакти, остатоци од предмети или под-фрагменти кои се пронајдени на локалитет. Поради тоа, секој фрагмент мора да има јасна логичка припадност.
     284
     285Фрагментот може:
     286 * директно да припаѓа на археолошки предмет преку `object_id`
     287 * да биде дел од друг фрагмент преку `parent_fragment_id`
     288
     289Но не смее истовремено да припаѓа и на предмет и на друг фрагмент, бидејќи тоа би создало нејасна и двојна хиерархија.
     290
     2913. **Причина за избор на тригер:** 
     292Овој тригер е избран затоа што се работи за доменско правило кое мора да се провери автоматски пред секој внес или ажурирање. Иако во табелата `Fragments` постои и `CHECK` ограничување за ова правило, тригерот дополнително овозможува појасна контрола и експлицитна порака за грешка.
     293
     294Со ова се добива подобра разбирливост при тестирање и при работа со апликацијата, бидејќи корисникот добива конкретна порака:
     295
     296{{{
     297Фрагмент не може да има и object и parent
     298}}}
     299
     3004. **Имплементација:** 
     301
     302Тригер функцијата е:
     303
     304{{{
     305CREATE OR REPLACE FUNCTION trg_fragment_validation()
     306RETURNS TRIGGER AS $$
     307BEGIN
     308    IF NEW.object_id IS NOT NULL AND NEW.parent_fragment_id IS NOT NULL THEN
     309        RAISE EXCEPTION 'Фрагмент не може да има и object и parent';
     310    END IF;
     311
     312    RETURN NEW;
     313END;
     314$$ LANGUAGE plpgsql;
     315}}}
     316
     317Тригерот се активира:
     318
     319{{{
     320CREATE TRIGGER trg_fragment_check
     321BEFORE INSERT OR UPDATE ON Fragments
     322FOR EACH ROW
     323EXECUTE FUNCTION trg_fragment_validation();
     324}}}
     325
     3265. **Логика на работа:** 
     327Тригерот се извршува пред секој `INSERT` или `UPDATE` врз табелата `Fragments`. Тој ја проверува новата вредност која треба да се внесе или ажурира преку `NEW`.
     328
     329Доколку и `NEW.object_id` и `NEW.parent_fragment_id` имаат вредност различна од `NULL`, записот се одбива и се фрла исклучок.
     330
     331Ова значи дека базата не дозволува фрагментот да има двојна припадност.
     332
     3336. **Бизнис логика:** 
     334Овој тригер ја имплементира логиката за зачувување на археолошкиот контекст на фрагментите. Во реална археолошка евиденција, важно е точно да се знае дали еден фрагмент е директен дел од предмет или е под-фрагмент од друг фрагмент.
     335
     336Ако ова правило не постои, би можело да се случи ист фрагмент да биде прикажан во две различни структури, што би предизвикало погрешни извештаи, неточна реконструкција на предметите и неконзистентна научна документација.
     337
     3387. **Пример на неправилен внес:** 
     339
     340{{{
     341INSERT INTO Fragments (object_id, parent_fragment_id, status_id)
     342VALUES (1, 2, 1);
     343}}}
     344
     345Овој внес се одбива затоа што фрагментот има и `object_id` и `parent_fragment_id`.
     346
     3478. **Заклучок:** 
     348`trg_fragment_check` е важен тригер за зачувување на правилната хиерархија на фрагментите. Тој спречува нелогични релации во археолошката документација и обезбедува секој фрагмент да има јасна и единствена припадност.
     349
     350
     351
     352=== Тригер 2: Проверка на одобрен истражувачки пристап (trg_access_check) ===
     353
     3541. **Намена:** 
     355Тригерот `trg_access_check` е наменет за валидација на записите во табелата `Researcher_Access`. Неговата цел е да спречи внесување на одобрен истражувачки пристап доколку не е наведен конкретен археолошки предмет.
     356
     3572. **Случај на употреба:** 
     358Во системот, истражувачите можат да побараат пристап до конкретни предмети за научна обработка, анализа или конзерваторска документација. Пристапот не смее да биде апстрактен или општ, туку мора да се однесува на точно определен артефакт.
     359
     360Одобрување пристап без конкретен предмет би било логички невалидно, бидејќи системот не би знаел до кој објект истражувачот добил дозвола.
     361
     3623. **Причина за избор на тригер:** 
     363Тригерот е избран затоа што ова правило е поврзано со бизнис логиката на процесот на одобрување пристап. Иако `object_id` во табелата `Researcher_Access` е дефиниран како `NOT NULL`, тригерот додава дополнителна проверка за конкретен случај: кога статусот на пристап е одобрен.
     364
     365На тој начин правилото е експлицитно документирано во базата и директно се поврзува со статусот `access_status_id = 6`, кој во податоците се користи за статусот „Одобрено“.
     366
     3674. **Имплементација:** 
     368
     369Тригер функцијата е:
     370
     371{{{
     372CREATE OR REPLACE FUNCTION trg_block_access()
     373RETURNS TRIGGER AS $$
     374BEGIN
     375    IF NEW.access_status_id = 6 AND NEW.object_id IS NULL THEN
     376        RAISE EXCEPTION 'Не може одобрен пристап без објект';
     377    END IF;
     378
     379    RETURN NEW;
     380END;
     381$$ LANGUAGE plpgsql;
     382}}}
     383
     384Тригерот се активира:
     385
     386{{{
     387CREATE TRIGGER trg_access_check
     388BEFORE INSERT ON Researcher_Access
     389FOR EACH ROW
     390EXECUTE FUNCTION trg_block_access();
     391}}}
     392
     3935. **Логика на работа:** 
     394Тригерот се извршува пред внесување нов запис во `Researcher_Access`.
     395
     396Проверува дали:
     397 * `access_status_id = 6`, односно пристапот е одобрен
     398 * `object_id IS NULL`, односно не е наведен предмет
     399
     400Доколку двата услови се исполнети, внесот се блокира.
     401
     4026. **Бизнис логика:** 
     403Овој тригер ја имплементира контролата на истражувачки пристап. Во контекст на културно наследство, предметите можат да имаат чувствителни информации, како точна локација на пронаоѓање, состојба, вредност, конзерваторски третмани или научна важност.
     404
     405Затоа секој одобрен пристап мора да биде поврзан со конкретен предмет. Ова спречува нејасни дозволи и овозможува прецизна ревизија на тоа кој корисник добил пристап до кој артефакт.
     406
     4077. **Заклучок:** 
     408`trg_access_check` обезбедува дополнителна безбедност и логичка исправност во процесот на одобрување истражувачки пристап. Тој спречува креирање на невалидни записи и помага системот да одржи точна евиденција за дозволите на истражувачите.
     409
     410
     411
     412=== Тригер 3: Спречување публикација без главен автор (trg_publication_check) ===
     413
     4141. **Намена:** 
     415Тригерот `trg_publication_check` е наменет за проверка на научните публикации пред нивно внесување или ажурирање. Неговата цел е да спречи публикација да постои без дефиниран главен автор.
     416
     4172. **Случај на употреба:** 
     418Во системот се чуваат научни публикации поврзани со археолошки предмети. Публикацијата може да има повеќе автори преку табелата `Publication_Authors`, но мора да постои еден главен автор во табелата `Publications` преку полето `main_author_id`.
     419
     420Главниот автор е важен затоа што претставува примарно лице одговорно за публикацијата, нејзината содржина и академската евиденција.
     421
     4223. **Причина за избор на тригер:** 
     423Тригерот е избран затоа што се работи за бизнис правило кое мора да важи и при внесување и при ажурирање на публикации. Иако ова правило може делумно да се реализира со `NOT NULL` constraint, тригерот овозможува експлицитна контрола и јасна порака за грешка.
     424
     425Дополнително, тригерот е корисен бидејќи во моделот `main_author_id` може да биде `NULL` на ниво на дефиниција на табела, но бизнис логиката бара да не се дозволува реално внесување публикација без главен автор.
     426
     4274. **Имплементација:** 
     428
     429Тригер функцијата е:
     430
     431{{{
     432CREATE OR REPLACE FUNCTION trg_pub_author_check()
     433RETURNS TRIGGER AS $$
     434BEGIN
     435    IF NEW.main_author_id IS NULL THEN
     436        RAISE EXCEPTION 'Публикацијата мора да има главен автор';
     437    END IF;
     438
     439    RETURN NEW;
     440END;
     441$$ LANGUAGE plpgsql;
     442}}}
     443
     444Тригерот се активира:
     445
     446{{{
     447CREATE TRIGGER trg_publication_check
     448BEFORE INSERT OR UPDATE ON Publications
     449FOR EACH ROW
     450EXECUTE FUNCTION trg_pub_author_check();
     451}}}
     452
     4535. **Логика на работа:** 
     454Тригерот се извршува пред секој `INSERT` или `UPDATE` врз табелата `Publications`.
     455
     456Доколку новата вредност за `main_author_id` е `NULL`, внесот или ажурирањето се прекинува и се фрла исклучок.
     457
     4586. **Бизнис логика:** 
     459Овој тригер ја имплементира академската логика на системот. Во археолошки и научен контекст, секоја публикација мора да има одговорен автор.
     460
     461Без ова правило, системот би можел да содржи публикации без јасна одговорност, што би довело до проблеми при цитирање, библиографска обработка и научна документација.
     462
     4637. **Заклучок:** 
     464`trg_publication_check` обезбедува секоја научна публикација да има главен автор. Со тоа се зачувува академскиот интегритет на податоците и се спречува внесување нецелосни публикации.
     465
     466
     467
     468=== Тригер 4: Автоматско поставување статус на фрагмент (trg_fragment_auto_status) ===
     469
     4701. **Намена:** 
     471Тригерот `trg_fragment_auto_status` е наменет за автоматско поставување статус на нов фрагмент при негово внесување во табелата `Fragments`.
     472
     4732. **Случај на употреба:** 
     474Кога се внесува нов фрагмент кој е поврзан со конкретен археолошки предмет преку `object_id`, системот автоматски му поставува иницијален статус.
     475
     476Ова е корисно затоа што при теренска работа или масовно внесување податоци може да се внесат голем број фрагменти, па рачното поставување статус за секој од нив би било подложно на грешки.
     477
     4783. **Причина за избор на тригер:** 
     479Тригерот е избран затоа што статусот треба автоматски да се постави во моментот на внесување, врз основа на вредноста на `object_id`.
     480
     481Ова правило е динамично: ако фрагментот е поврзан со предмет, тогаш добива статус. Затоа е соодветно да се користи `BEFORE INSERT` тригер, кој може да ја промени вредноста на `NEW.status_id` пред записот да биде зачуван.
     482
     4834. **Имплементација:** 
     484
     485Тригер функцијата е:
     486
     487{{{
     488CREATE OR REPLACE FUNCTION trg_auto_fragment_status()
     489RETURNS TRIGGER AS $$
     490BEGIN
     491    IF NEW.object_id IS NOT NULL THEN
     492        NEW.status_id := 1;
     493    END IF;
     494
     495    RETURN NEW;
     496END;
     497$$ LANGUAGE plpgsql;
     498}}}
     499
     500Тригерот се активира:
     501
     502{{{
     503CREATE TRIGGER trg_fragment_auto_status
     504BEFORE INSERT ON Fragments
     505FOR EACH ROW
     506EXECUTE FUNCTION trg_auto_fragment_status();
     507}}}
     508
     5095. **Логика на работа:** 
     510Тригерот се активира пред секој внес во `Fragments`.
     511
     512Ако новиот фрагмент има вредност во `object_id`, тогаш автоматски се поставува:
     513
     514{{{
     515NEW.status_id := 1;
     516}}}
     517
     518Со тоа фрагментот добива иницијален статус без корисникот да мора рачно да го внесе.
     519
     5206. **Бизнис логика:** 
     521Овој тригер ја имплементира автоматизацијата на теренската и лабораториската евиденција на фрагменти. Во систем за културно наследство, фрагментите често се внесуваат во голем број, особено при археолошки ископувања или лабораториска обработка.
     522
     523Автоматското поставување статус обезбедува секој фрагмент кој е поврзан со предмет да има валиден почетен статус, што го олеснува понатамошното следење, класификација и конзервација.
     524
     5257. **Заклучок:** 
     526`trg_fragment_auto_status` ја намалува можноста за човечка грешка при внесување фрагменти и обезбедува поголема конзистентност во базата. Тој е особено корисен при масовно внесување археолошки материјал.
     527
     528
     529
     530=== Тригер 5: Проверка на совпаѓање помеѓу проект и предмет кај истражувачки пристап (trg_researcher_access_project_match) ===
     531
     5321. **Намена:** 
     533Тригерот `trg_researcher_access_project_match` е наменет за проверка дали конзерваторскиот проект наведен во `Researcher_Access` навистина се однесува на истиот предмет за кој се бара истражувачки пристап.
     534
     5352. **Случај на употреба:** 
     536Во системот, истражувачкиот пристап може да биде поврзан со конкретен конзерваторски проект преку `conservation_project_id`. Секој конзерваторски проект во табелата `Conservation_Projects` е поврзан со точно одреден предмет преку `object_id`.
     537
     538Проблемот се јавува ако истражувач побара пристап до еден предмет, но во барањето наведе конзерваторски проект кој реално припаѓа на друг предмет. Таков запис би бил логички неконзистентен и би можел да доведе до погрешно одобрување на пристап.
     539
     5403. **Причина за избор на тригер:** 
     541Овој тригер е избран затоа што правилото бара споредба на вредности од две различни табели:
     542
     543 * `Researcher_Access.object_id`
     544 * `Conservation_Projects.object_id`
     545
     546Обичен `FOREIGN KEY` може да провери дали `conservation_project_id` постои во `Conservation_Projects`, но не може сам да провери дали тој проект се однесува на истиот `object_id` кој е наведен во барањето за пристап.
     547
     548Затоа се користи тригер, бидејќи тој може да изврши дополнителен `SELECT`, да ја прочита вредноста `object_id` од проектот и да ја спореди со новиот запис во `Researcher_Access`.
     549
     5504. **Имплементација:** 
     551
     552Тригер функцијата е:
     553
     554{{{
     555CREATE OR REPLACE FUNCTION trg_validate_project_object_match()
     556RETURNS TRIGGER AS $$
     557DECLARE
     558    v_project_object_id BIGINT;
     559BEGIN
     560    IF NEW.conservation_project_id IS NULL THEN
     561        RETURN NEW;
     562    END IF;
     563
     564    SELECT object_id
     565    INTO v_project_object_id
     566    FROM Conservation_Projects
     567    WHERE project_id = NEW.conservation_project_id;
     568
     569    IF v_project_object_id <> NEW.object_id THEN
     570        RAISE EXCEPTION 'Конзерваторскиот проект % не припаѓа на објектот %. Пристапот е одбиен.',
     571            NEW.conservation_project_id, NEW.object_id;
     572    END IF;
     573
     574    RETURN NEW;
     575END;
     576$$ LANGUAGE plpgsql;
     577}}}
     578
     579Тригерот се активира:
     580
     581{{{
     582CREATE TRIGGER trg_researcher_access_project_match
     583BEFORE INSERT OR UPDATE ON Researcher_Access
     584FOR EACH ROW
     585EXECUTE FUNCTION trg_validate_project_object_match();
     586}}}
     587
     5885. **Логика на работа:** 
     589Тригерот се активира пред секој `INSERT` или `UPDATE` во `Researcher_Access`.
     590
     591Прво проверува дали `NEW.conservation_project_id` е `NULL`.
     592
     593Ако нема поврзан проект, нема што да се проверува и записот продолжува.
     594
     595Ако постои поврзан проект, тригерот го пронаоѓа `object_id` од табелата `Conservation_Projects` за тој проект:
     596
     597{{{
     598SELECT object_id
     599INTO v_project_object_id
     600FROM Conservation_Projects
     601WHERE project_id = NEW.conservation_project_id;
     602}}}
     603
     604Потоа го споредува тој `object_id` со `NEW.object_id`.
     605
     606Ако вредностите не се исти, записот се одбива.
     607
     6086. **Бизнис логика:** 
     609Овој тригер имплементира едно од најважните правила за контрола на истражувачки пристап. Во системот, пристапот не смее да се одобри преку проект кој не се однесува на истиот предмет.
     610
     611На пример, ако конзерваторски проект е креиран за предмет А, истражувачот не смее да го користи тој проект како основа за пристап до предмет Б. Тоа би создало сериозна неконзистентност во системот и би можело да доведе до неовластен пристап до погрешен артефакт.
     612
     613Ова е особено важно кај културното наследство, бидејќи предметите можат да имаат различен степен на заштита, различни истражувачки ограничувања и различна институционална сопственост.
     614
     6157. **Зошто не е доволен FOREIGN KEY:** 
     616Стандардниот `FOREIGN KEY` constraint може да провери само дали вредноста `conservation_project_id` постои како `project_id` во `Conservation_Projects`.
     617
     618Но правилото овде е посложено. Треба да се провери дали:
     619
     620{{{
     621Researcher_Access.conservation_project_id -> Conservation_Projects.project_id
     622}}}
     623
     624и истовремено дали:
     625
     626{{{
     627Researcher_Access.object_id = Conservation_Projects.object_id
     628}}}
     629
     630Ова е меѓутабеларна логичка проверка и затоа е соодветно имплементирана со тригер.
     631
     6328. **Заклучок:** 
     633`trg_researcher_access_project_match` обезбедува логичка конзистентност помеѓу истражувачките барања, предметите и конзерваторските проекти. Овој тригер спречува сериозни грешки во пристапот и ја зајакнува безбедноста и точноста на системот.