Nieco zmieniony diagram ERD
CREATE TABLE friends ( id serial NOT NULL, id_user integer NOT NULL, id_friend integer NOT NULL, status smallint NOT NULL, CONSTRAINT friends_pkey PRIMARY KEY (id), CONSTRAINT friends_id_friend_fkey FOREIGN KEY (id_friend) REFERENCES users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT friends_id_user_fkey FOREIGN KEY (id_user) REFERENCES users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE ) CREATE TABLE tags ( id serial NOT NULL, "name" text, id_user integer NOT NULL, color integer, CONSTRAINT tags_pkey PRIMARY KEY (id), CONSTRAINT "owner" FOREIGN KEY (id_user) REFERENCES users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE ) CREATE TABLE user_event ( id serial NOT NULL, id_user integer NOT NULL, id_event integer NOT NULL, CONSTRAINT user_event_pkey PRIMARY KEY (id), CONSTRAINT user_event_id_event_fkey FOREIGN KEY (id_event) REFERENCES events (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE, CONSTRAINT user_event_id_user_fkey FOREIGN KEY (id_user) REFERENCES users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE ) CREATE TABLE users ( id serial NOT NULL, "name" character varying(30), "login" text NOT NULL, "password" character(32) NOT NULL, session_cookie character(32), CONSTRAINT id PRIMARY KEY (id), CONSTRAINT users_login_key UNIQUE (login) ) CREATE TABLE events ( id serial NOT NULL, id_tag integer, startdate date, title text, description text, duration integer, CONSTRAINT events_pkey PRIMARY KEY (id), CONSTRAINT events_id_tag_fkey FOREIGN KEY (id_tag) REFERENCES tags (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE SET NULL )
1NF
2NF
3NF
W projekcie zastosowane zostało mapowanie OR obsługiwane przez bibliotekę Hibernate.
Konfiguracja Hibernate'a
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated May 3, 2011 3:57:34 PM by Hibernate Tools 3.4.0.CR1 --> <hibernate-mapping> <class name="model.User" table="users"> <id name="id" type="long"> <generator class="identity"/> </id> <property generated="never" lazy="false" name="name"/> <property generated="never" lazy="false" name="login"/> <property generated="never" lazy="false" name="password"/> <property column="session_cookie" generated="never" lazy="false" name="sessionCookie"/> <set name="events" sort="unsorted" table="user_event"> <key column="id_user"/> <many-to-many class="model.Event" column="id_event" unique="false"/> </set> <set inverse="true" name="friends" sort="unsorted" table="friends"> <key column="id_user"/> <one-to-many class="model.Friend"/> </set> <set inverse="true" name="tags" sort="unsorted" table="tags"> <key column="id_user"/> <one-to-many class="model.Tag"/> </set> </class> <class name="model.Friend" table="friends"> <id name="id" type="long"> <generator class="identity"/> </id> <property generated="never" lazy="false" name="status"/> <many-to-one column="id_user" name="user" lazy="false"/> <many-to-one column="id_friend" name="friend" lazy="false"/> </class> <class name="model.Event" table="events"> <id name="id" type="long"> <generator class="identity"/> </id> <many-to-one column="id_tag" name="tag" lazy="false"/> <property generated="never" lazy="false" name="startDate"/> <property generated="never" lazy="false" name="title"/> <property generated="never" lazy="false" name="description"/> <property generated="never" lazy="false" name="duration"/> </class> <class name="model.Tag" table="tags"> <id name="id" type="long"> <generator class="identity"/> </id> <property generated="never" lazy="false" name="name"/> <property generated="never" lazy="false" name="color"/> <many-to-one column="id_user" name="user" lazy="false"/> </class> </hibernate-mapping>
Logowanie użytkownika:
Podczas logowania sprawdzane jest czy w bazie danych istnieje podany login i hasło:
select user0_.id as col_0_0_ from public.users user0_ where user0_.login=? and user0_.password=?
Następnie po sprawdzeniu pobierane są dane użytkownika:
select user0_.id as id0_, user0_.name as name0_, user0_.login as login0_, user0_.password as password0_, user0_.session_cookie as session5_0_ from public.users user0_ where user0_.login=?
W następnej kolejności pobierane są dodatkowe dane powiązane z bieżącym użytkownikiem. Wydarzenia pobierane są poprzez wewnętrzne złączenie tabel user_event (tabela asocjacyjna wiążąca użytkowników z wydarzeniami) oraz events (tabela z wydarzeniami):
select […] from public.user_event events0_ inner join public.events event1_ on events0_.id_event=event1_.id where events0_.id_user=?
Dla każdego wydarzenia pobierane są etykiety (dla każdej użytej etykiety):
select tag0_.id as id4_0_, tag0_.name as name4_0_, tag0_.color as color4_0_, tag0_.id_user as id4_4_0_ from public.tags tag0_ where tag0_.id=?
Następnie pobierane są informacje o znajomych użytkownika:
select […] from public.friends friends0_ where friends0_.id_user=?
Ponieważ tabela friends jest tabelą asocjacyjną, konieczne jest pobranie reszty danych (każde zaytanie oddzielnie, ponieważ tabela friends z punktu widzenia mappera nie jest tablicą asocjacyjną, gdyż mapuje ona na nową klasę Friend, która posiada wskaźniki do użytkownika, jego znajomego, oraz dodatkowo posiada informacje o stopniu znajomości – znojomy, zaproszony, zablokowany):
select user0_.id as id0_0_, user0_.name as name0_0_, user0_.login as login0_0_, user0_.password as password0_0_, user0_.session_cookie as session5_0_0_ from public.users user0_ where user0_.id=?
Ostatecznie pobierane są także wszystkie etykiety, jakimi może zarządzać dany użytkownik:
select tags0_.id_user as id4_0_1_, tags0_.id as id1_, tags0_.id as id4_0_, tags0_.name as name4_0_, tags0_.color as color4_0_, tags0_.id_user as id4_4_0_ from public.tags tags0_ where tags0_.id_user=?
Wyszukiwanie znajomych:
Wystarczy jedno zapytanie o użytkowników, których nazwa lub login pasują do wzorca
select user0_.id as id0_, user0_.name as name0_, user0_.login as login0_, user0_.password as password0_, user0_.session_cookie as session5_0_ from public.users user0_ where user0_.login like ? or user0_.name like ?
Wysyłanie zaproszenia do znajomego:
Wysłanie zapytania typu insert:
insert into public.friends (status, id_user, id_friend) values (?, ?, ?)
Dodawanie wydarzenia:
Wysyłane są dwa zapytania typu insert, ponieważ należy dodać dane zarówno do tabeli z wydarzeniami, jak i do tabeli asocjacyjnej:
insert into public.events (id_tag, startDate, title, description, duration) values (?, ?, ?, ?, ?)
oraz:
insert into public.user_event (id_user, id_event) values (?, ?)
Porównywanie kalendarzy:
Dla każdego wybranego do porównania użytkownika , konieczne jest pobranie listy jego wydarzeń. Jest to spowodowane mechanizmem lazy-load. Zbiory (w tym wypadku zbiory wydarzeń) ładowane są dopiero przy pierwszym ich użyciu. Dlatego też dla każdego wybranego użytkownika nastąpi wysłanie zapytania:
select […] from public.user_event events0_ inner join public.events event1_ on events0_.id_event=event1_.id where events0_.id_user=?