Autorzy: Jakub Gorzała, Łukasz Kowalski
Projekt bazy danych, która będzie wykorzystywana w projekcie z przedmiotu Technologie i programowanie WWW. Projekt ten ma na celu stworzenie portalu zawierającego rozkłady jazdy minibusów z całej polski.
W sieci istnieje strona o podobnej tematyce, lecz posiada ona sporo wad. Po pierwsze jest wykonana w bardzo prostej technologii (zwykły html + css), jest nieczytelna przez co prezentuje się bardzo nie atrakcyjnie i nie wzbudza zainteresowania. Nie jest aktualizowana, więc informacje na niej zawarte mogą być mylące dla użytkowników. Strona w głównej mierze jest zbiorem linków do poszczególnych przewoźników, a nie centralnym zbiorem rozkładów, przez co wyszukiwanie interesującego połączenia jest trudne. Storna nie posiada możliwości wystawiania opinii ani komentarzy przewoźnikom, a takie informacje mogły by być przydatne.
Główne funkcjonalności portalu:
Baza danych będzie przechowywać informacje o:
@Entity @Table(name="COMPANIES") @NamedQueries({ @NamedQuery(name="findCompanyByName", query="SELECT c FROM Company c WHERE c.name = :name"), @NamedQuery(name="findCompanyByOwnerName", query="SELECT c FROM Company c WHERE c.owner.name = :name") }) public class Company implements Serializable { private static final long serialVersionUID = 5074588959885714521L; @GeneratedValue(strategy=GenerationType.AUTO) private long companyid; @Column(nullable=false) private String name; @Column(nullable=false) private String mail; @ManyToOne private User owner; @OneToMany(mappedBy="company", targetEntity=Opinion.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER) private Set<Opinion> opinions; @OneToMany(mappedBy="owner", targetEntity=Course.class, cascade=CascadeType.ALL, fetch=FetchType.LAZY) private Set<Course> courses; } @Entity @Table(name="COURSES") @NamedQuery(name="findCourseByCompany", query="SELECT c FROM Course c WHERE c.owner.name = :name") public class Course implements Serializable { private static final long serialVersionUID = 3008699718560976506L; @GeneratedValue(strategy=GenerationType.AUTO) private long courseid @OneToOne private Company owner; @Column(nullable=true) private String description; @OneToMany(mappedBy="course", targetEntity=Stop.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER) private List<Stop> stops; } @Entity @Table(name="OPINIONS") @NamedQuery(name="findOpinionByCompany", query="SELECT o FROM Opinion o WHERE o.company.name = :name") public class Opinion implements Serializable { private static final long serialVersionUID = 2475121744579807544L; @GeneratedValue(strategy=GenerationType.AUTO) private long opinionid; @ManyToOne private Company company; @Column(nullable=true) private boolean positive; @Column(nullable=true) private String description; } @Entity @Table(name="PLACES") @NamedQueries({ @NamedQuery(name="findPlaceByName", query="SELECT p FROM Place p WHERE p.city = :city AND p.name = :name"), @NamedQuery(name="autocompletePlace", query="SELECT p FROM Place p WHERE p.city LIKE :city AND p.name LIKE :name"), @NamedQuery(name="autocompletePlaceByCity", query="SELECT p FROM Place p WHERE p.city LIKE :city"), @NamedQuery(name="autocompletePlaceByName", query="SELECT p FROM Place p WHERE p.name LIKE :name") }) public class Place implements Serializable { private static final long serialVersionUID = 7561920390812143011L; @GeneratedValue(strategy=GenerationType.AUTO) private long placeid; @Column(nullable=false) private String city; @Column(nullable=false) private String name; @Column(nullable=true) private BigDecimal lon; @Column(nullable=true) private BigDecimal lat; } @Entity @Table(name="STOPS") @NamedQuery(name="findStopByPlace", query="SELECT s FROM Stop s WHERE s.place.city = :city and s.place.name = :name") public class Stop implements Serializable { private static final long serialVersionUID = 2015220800633676479L; @GeneratedValue(strategy=GenerationType.AUTO) private long stopid; @ManyToOne private Course course; @OneToOne private Place place; @Column(nullable=false) private int orderNumber; @Column(nullable=true) private BigDecimal cost; @Column(nullable=true) private String hours; } @Entity @Table(name="USERS") public class User implements Serializable { private static final long serialVersionUID = 8651753619995718647L; @GeneratedValue(strategy=GenerationType.AUTO) private long userid; @Column(nullable=false) private String name; @Column(nullable=false) private String password; @Column(nullable=false) private String mail; @Column(nullable=false) private int role = 1; @OneToMany(mappedBy="owner", targetEntity=Company.class, cascade=CascadeType.ALL, fetch=FetchType.EAGER) private Set<Company> companies; }
CREATE TABLE companies ( id BIGINT NOT NULL, "name" CHARACTER VARYING(255) NOT NULL, mail CHARACTER VARYING(255) NOT NULL, owner_id BIGINT, CONSTRAINT companies_pkey PRIMARY KEY (id), CONSTRAINT fk51e1f1bbedbce178 FOREIGN KEY (owner_id) REFERENCES users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE TABLE courses ( id BIGINT NOT NULL, description CHARACTER VARYING(255), hours CHARACTER VARYING(255), owner_id BIGINT, CONSTRAINT courses_pkey PRIMARY KEY (id), CONSTRAINT fk63e4af986eae0d5e FOREIGN KEY (owner_id) REFERENCES companies (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE TABLE opinions ( id BIGINT NOT NULL, positive BOOLEAN, description CHARACTER VARYING(255), company_id BIGINT, CONSTRAINT opinions_pkey PRIMARY KEY (id), CONSTRAINT fk176ead31d905f754 FOREIGN KEY (company_id) REFERENCES companies (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE TABLE places ( id BIGINT NOT NULL, city CHARACTER VARYING(255) NOT NULL, "name" CHARACTER VARYING(255) NOT NULL, lon NUMERIC(19,2), lat NUMERIC(19,2), CONSTRAINT places_pkey PRIMARY KEY (id) ) CREATE TABLE stops ( id BIGINT NOT NULL, ordernumber INTEGER NOT NULL, "cost" NUMERIC(19,2), lag NUMERIC(19,2), place_id BIGINT, course_id BIGINT, CONSTRAINT stops_pkey PRIMARY KEY (id), CONSTRAINT fk4b9009137509994 FOREIGN KEY (place_id) REFERENCES places (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT fk4b90091894e45e0 FOREIGN KEY (course_id) REFERENCES courses (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE TABLE users ( id BIGINT NOT NULL, "name" CHARACTER VARYING(255) NOT NULL, "password" CHARACTER VARYING(255) NOT NULL, mail CHARACTER VARYING(255) NOT NULL, "role" INTEGER NOT NULL, CONSTRAINT users_pkey PRIMARY KEY (id) ) CREATE SEQUENCE hibernate_sequence INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1;
Wydaje się, że baza danych spełnia założenia 3NF. Wynika to z faktu, że przechowywane w niej dane są istnotnie atomiczne - z punktu widzenia implementacji projektu. W każdej tabeli atrybuty są w pełni bezpośrednio zależne od klucza głównego. Generalnie baza była projektowana tak by przy możlie maksymalnej funkcjonalności tabel, zapewnić trzecią postać normalną.
Kwerendy i zapytania wynikają z mechanizmu mapowania obiektowo relacyjnego w j2ee i są poniekąd dostarczone przez klasę EntityManager standardu JPA Hibernate. Pozostałe zapytania w celu optymalizacji wydajności pracy aplikacji zrealizowane zostały jako NamedQuery - zapytania prekompilowane i stworzone przy użyciu składni HQL - Hibernate Query Language. Można je zobaczyć nad kodem encji do których przynależą.
Aplikacja zrealizowana jest na bazie wzorca projektowego MVC (model widok kotroller). Sklada sie z 3 wyraznie wyrożnionych warstw:
Patrz punkt 11. Projektowanie tabel, kluczy, kluczy obcych, powiązań między tabelami, indeksów.
-formularz rejestracji użytkownika
-formularz logowania użytkownika
-formularz zakładania firmy przez użytkownika
-formularz edycji danych użytkownika
-formularz dodawania komentarzy
-formularz dodawania połączenia
-formularz wyszukiwania połączeń