Kowalski Marcin 156439 Wrocław, dn. 3.06.2009 Jaśkiewicz Kamil 148592 Bazy Danych 1 Podstawy Projekt Temat: Baza danych do zarządzania projektami Spis treści Założenia Projektowe...1 Schemat Bazy Danych...1 Funkcje sprawdzające spójność danych...3 Triggery...4 Interfejs Graficzny...5 Literatura...5 Założenia Projektowe Z dostępnych tematów postanowiliśmy zrealizować bazę danych do zarządzania projektami. Cała baza danych miała powstawać na bazie PHP, Apache i MySQL. Interfejs bazy jest graficzny. Cała baza danych wzorowana jest na dotproject opensource'owym narzędziu do zarządzania projektami. Z dotproject zapożyczony jest ogólny schemat bazy danych oraz, po zaaplikowanie pewnych modyfikacji, same definicje tabel w bazie. Zmieniony został silnik na InnoDB. Pozostałe części bazy danych są już efektem naszej pracy. Ponieważ cały schemat bazy danych dotproject jest zbyt duży by dało się go umieścić w dokumencie dodany został jako załącznik do pliku pdf. Schemat Bazy Danych Realizowaną bazą danych jest baza do zarządzania projektami. Ogólny schemat bazy danych przedstawiony został na rysunku 1. -1-
Rys 1 Ogólny Schemat bazy danych Cała baza składa się 8 tabel. Tabele podstawowe to companies firmy, departments departamenty, projects projekty, tasks zadania, contacts kontakty. Tabele te są zależne od siebie w sposób hierarchiczny, z czego najważniejszą tabelą jest companies tabele projects i departments mają klucze obce przypisane do tej tabeli. Następne z kolei do projects lub departments. Dodatkowo istnieją tabele pomocnicze project_departments i task_contacts kojarzące odpowiednio projekty i departamenty oraz ludzi i zadania. Ostatnią tabelą jest tabela dictionary. Tabela ta została tutaj umieszczona w celu uniknięcia definiowania zmiennych typu enum. W początkowym projekcie bazy danych istniało wiele pól wymagających wartości typu enum przykładowo project_priority gdzie mieliśmy wartości: Low, Normal, High. Zrezygnowaliśmy z takiej konstrukcji na rzecz wprowadzenia słownika. Konstrukcja słownika pokazana została na fragmencie kodu nr 1. Frarment kodu nr 2 przedstawia przykładowy wpis w słowniku. Teraz wszystkie wartości typu enum zostały zastąpione wartościami typu TINYINT każda jako klucz obcy do tabeli dictionary. Wszystkie wartości słownikowe wczytywane są do niego już przy tworzeniu bazy danych. -2-
CREATE TABLE IF NOT EXISTS `pm`.`dictionary` ( `dict_id` TINYINT NOT NULL, `dict_group` VARCHAR(30) NOT NULL, `name` VARCHAR (30) NOT NULL, PRIMARY KEY (dict_id) )ENGINE=InnoDb; Fragment kodu nr 1. INSERT INTO dictionary VALUES ('13', "project_priority", "Low"); Fragment kodu nr 2. Aby dane mogły być wygodnie przeglądane do wszystkich tabel korzystających ze słownika utworzyliśmy stosowne widoki. Fragment kodu nr 3 pokazuje przykład takiego widoku. CREATE VIEW vw_companies AS SELECT c.*, ct.name AS type FROM companies AS c LEFT JOIN dictionary AS ct ON c.company_type=ct.dict_id; Fragment kodu nr 3. Funkcje sprawdzające spójność danych Jak wcześniej zaznaczono cała baza danych zbudowana jest w sposób hierarchiczny. Praktycznie każda z podstawowych tabel poza compnies posiada klucze obce do innych tabel. Dlatego też w celu zachowania spójności danych utworzyliśmy funkcje sprawdzające czy dane znajdujące się lub takie które dopiero mają zostać umieszczone do którejś tabeli mają odpowiednie wartości. Ogólna każda funkcja sprawdzająca przyjmuje argumenty czyli dane do sprawdzenia, jako wynik zwraca wartość INT 1 - dane są spójne lub 0 - dane nie są spójne. Fragment kodu nr 4 pokazuje przykładową funkcję sprawdzającą czy dany departament może zajmować się danym projektem. Każdy projekt przypisany jest do jakiejś firmy, każdy departament należy do jakiejś firmy. Jeżeli w obydwu przypadkach to ta sama firma wtedy dane uznajemy za spójne. Funkcje zbudowane są prosto, w działaniu korzystają wyłącznie z poleceń SELECT i IF. Podczas testów funkcje działały poprawnie. Do przedstawionej poniżej istnieje jeszcze jedna, analogiczna funkcja sprawdzająca skojarzenia zadań (tasks) z osobami (contacts). DELIMITER // CREATE FUNCTION Check_Dept_Project(Dept_id INT(10), Project_id INT(10)) -3-
RETURNS INT BEGIN DECLARE s INT(10); SELECT dept_company_id from departments d where d.dept_id=dept_id into s; IF s NOT IN ( SELECT project_company_id FROM projects p WHERE p.project_id=project_id) THEN SET s = '0'; ELSE SET s = '1'; END IF; RETURN s; END // DELIMITER ; Fragment kodu nr 4. Podobne zadanie spełnia funkcja sprawdzająca czy dana wartość słownikowa może być przypisana pod odpowiednie pole (tak, by nie dało się przykładowo przypisać do project_type wartości z company_type). Funkcja ta w analogiczny sposób do opisanych wyżej przyjmuje argumenty i zwraca wynik, które także należy interpretować w taki sam sposób. Triggery Aby powyższe funkcje miały sens należało je zaimplementować w triggerach uruchamianych przed umieszczeniem nowych wartości w tabelach. Wszystkie triggery przygotowane do zachowania spójności danych działają identycznie najpierw uruchamiana jest funkcja, która sprawdza czy dana mogą zostać umieszczone w tablicy. Jeśli funkcja zwróci wartość 1, trigger nic nie robi. Jeśli funkcja zwraca wartość 0 trigger wywołuje błąd poprzez odwołanie się do nieistniejącej kolumny w tablicy departments. Błąd powoduje, że dane nie zostają umieszczone. Jak się okazało był to jedyny sposób by w triggerze odrzucić nowe dane, MySql nie dysponuje funkcjami CANCEL INSERT. Kod takiego triggera pokazany jest na fragmencie kodu nr 5. DELIMITER // CREATE TRIGGER test_dict_company BEFORE INSERT ON `companies` FOR EACH ROW BEGIN DECLARE s INT; SET s='1'; -4-
IF s NOT IN (select Check_Dict (NEW.company_type, 'company_type')) THEN (select `Nieprawidlowa wartosc slownikowa` from departments into s); END IF; END// DELIMITER ; Fragment kodu nr 5 Jak zaznaczono wcześniej baza ma bardzo hierarchiczny charakter. W takim razie należało przemyśleć sytuację w której usunięta zostanie firma, do której przypisane są projekty, do których mamy przypisane zadania. Rozwiązanie, które zaproponowaliśmy polega na kolejnym usuwaniu danych od najmniej znaczącej tabeli (w tym wypadku od tabeli tasks). Wadą takiego rozwiązania jest to, że usunąwszy firmę użytkownik może ze zgrozą stwierdzić, że zniknęła mu połowa bazy danych. Dlatego, już z poziomu php, zaimplementowaliśmy stosowne ostrzeżenie. Interfejs Graficzny Podczas projektowania interfejsu graficznego postawiliśmy na przejrzystość i funkcjonalność. Użytkownik ma dostęp do wszystkich podstawowych tabel Companies, Projects, Tasks, Contacts oraz do definiowania typów słownikowych. Do każdej z powyższych tabel może dodać wpis, usunąć go lub edytować. Edytowalne są wszystkie pola danego wpisu prócz jego pola id (to jest widoczne tylko z poziomu MySql). Wszystkie wartości słownikowe oraz klucze obce do innych tabel odnoszące się do wartości id (przykładowo w tabeli projects pole project_company_id czyli pole informujące jaka firma projektem się zajmuje) są wybieralne z rozwijanej listy, co stanowi dodatkowe zabezpieczenia bazy danych uniemożliwia przypisanie tym polom wartości niepożądanych. Literatura Notatki z wykładu Bazy Danych Podstawy www.dotproject.net www.mysql.com Elizabeth Naramore, Jason Garner, Yann Le Scouarnec, Jeremy Stolz, Micheal K. Glass PHP5, Apache i MySQL od podstaw -5-