Spis treści

Projekt logiczny

1. Projektowanie w oparciu o zdefiniowany diagram ERD

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
)

2. Słowniki danych

3. Analiza zależności funkcyjnych i normalizacja tabel

1NF

2NF

3NF

4. Projektowanie operacji na danych

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>

Zapytania SQL

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=?