====== Projekt logiczny ====== ==== 1. Projektowanie tabel, kluczy, kluczy obcych, powiązań między tabelami, indeksów, etc. w oparciu o zdefiniowany diagram ERD ==== W naszym projekcie wykorzystaliśmy silnik bazy danych Microsoft SQL Server 2008 Express Edition. Poniżej załączony jest kod odpowiedzialny za generowanie schematu bazy danych w T-SQL. === Utworzenie struktury tabel === create table [DataObject] ( DataObjectId INT IDENTITY NOT NULL, Path NVARCHAR(255) null, OriginalFilename NVARCHAR(255) null, primary key (DataObjectId) ) create table [Game] ( GameId INT IDENTITY NOT NULL, Name NVARCHAR(255) null, Description NVARCHAR(255) null, Date DATETIME null, Resolved BIT null, PhotoID INT null, UserID INT null, primary key (GameId) ) create table [GameAccessControlList] ( GameAccessControlListId INT IDENTITY NOT NULL, Permission NVARCHAR(255) null, UserID INT null, GameID INT null, primary key (GameAccessControlListId) ) create table [Response] ( ResponseId INT IDENTITY NOT NULL, Date DATETIME null, Comment NVARCHAR(255) null, Correctness BIT null, GameID INT null, UserID INT null, PhotoID INT null, primary key (ResponseId) ) create table [ResponseAccessControlList] ( ResponseAccessControlListId INT IDENTITY NOT NULL, Permission NVARCHAR(255) null, UserID INT null, ResponseID INT null, primary key (ResponseAccessControlListId) ) create table [Role] ( RoleId INT IDENTITY NOT NULL, Name NVARCHAR(255) null, primary key (RoleId) ) create table RolesToUsers ( RoleID INT not null, UserID INT not null ) create table [User] ( UserId INT IDENTITY NOT NULL, Username NVARCHAR(255) null, Email NVARCHAR(255) null, primary key (UserId) ) create table FacebookUser ( UserID INT not null, FacebookId BIGINT null unique, primary key (UserID) ) create table LocalUser ( UserID INT not null, Password NVARCHAR(255) null, Username NVARCHAR(255) null unique, primary key (UserID) ) === Utworzenie kluczy obcych === alter table [Game] add constraint FK_Game_Photo foreign key (PhotoID) references [DataObject] alter table [Game] add constraint FK_Game_User foreign key (UserID) references [User] alter table [GameAccessControlList] add constraint FK_GameAccessControlList_User foreign key (UserID) references [User] alter table [GameAccessControlList] add constraint FK_GameAccessControlList_Game foreign key (GameID) references [Game] alter table [Response] add constraint FK_Response_Game foreign key (GameID) references [Game] alter table [Response] add constraint FK_Response_User foreign key (UserID) references [User] alter table [Response] add constraint FK_Response_Photo foreign key (PhotoID) references [DataObject] alter table [ResponseAccessControlList] add constraint FK_ResponseAccessControlList_User foreign key (UserID) references [User] alter table [ResponseAccessControlList] add constraint FK_ResponseAccessControlList_Response foreign key (ResponseID) references [Response] alter table RolesToUsers add constraint FK_Role_User foreign key (UserID) references [User] alter table RolesToUsers add constraint FK_User_Role foreign key (RoleID) references [Role] alter table FacebookUser add constraint FK_User foreign key (UserID) references [User] alter table LocalUser add constraint FK_User2 foreign key (UserID) references [User] ==== 2. Słownik danych ==== ^Nazwa tabeli ^Nazwa pola ^Numer pola ^Wartosc domyslna ^Czy nullowalne ^Typ pola ^ |DataObject |DataObjectId |1 |NULL |NO |int |NULL |DataObject |OriginalFilename |3 |NULL |YES |nvarchar |255 |DataObject |Path |2 |NULL |YES |nvarchar |255 |FacebookUser |FacebookId |2 |NULL |YES |bigint |NULL |FacebookUser |User_id |1 |NULL |NO |int |NULL |Game |Date |4 |NULL |YES |datetime |NULL |Game |Description |3 |NULL |YES |nvarchar |255 |Game |GameId |1 |NULL |NO |int |NULL |Game |Name |2 |NULL |YES |nvarchar |255 |Game |Photo_id |5 |NULL |YES |int |NULL |Game |Resolved |7 |NULL |YES |bit |NULL |Game |User_id |6 |NULL |YES |int |NULL |GameAccessControlList |Game_id |4 |NULL |YES |int |NULL |GameAccessControlList |GameAccessControlListId |1 |NULL |NO |int |NULL |GameAccessControlList |Permission |2 |NULL |YES |nvarchar |255 |GameAccessControlList |User_id |3 |NULL |YES |int |NULL |LocalUser |Password |2 |NULL |YES |nvarchar |255 |LocalUser |User_id |1 |NULL |NO |int |NULL |LocalUser |Username |3 |NULL |YES |nvarchar |255 |Response |Comment |4 |NULL |YES |nvarchar |255 |Response |Correctness |5 |NULL |YES |bit |NULL |Response |Date |2 |NULL |YES |datetime |NULL |Response |Game_id |6 |NULL |YES |int |NULL |Response |Photo_id |9 |NULL |YES |int |NULL |Response |ResponseId |1 |NULL |NO |int |NULL |Response |User_id |8 |NULL |YES |int |NULL |ResponseAccessControlList |Permission |2 |NULL |YES |nvarchar |255 |ResponseAccessControlList |Response_id |4 |NULL |YES |int |NULL |ResponseAccessControlList |ResponseAccessControlListId |1 |NULL |NO |int |NULL |ResponseAccessControlList |User_id |3 |NULL |YES |int |NULL |Role |Name |2 |NULL |YES |nvarchar |255 |Role |RoleId |1 |NULL |NO |int |NULL |RolesToUsers |Role_id |1 |NULL |NO |int |NULL |RolesToUsers |User_id |2 |NULL |NO |int |NULL |User |Email |3 |NULL |YES |nvarchar |255 |User |UserId |1 |NULL |NO |int |NULL |User |Username |2 |NULL |YES |nvarchar |255 |NULL |NULL |NULL |NULL |NULL |NULL |NULL ==== 3. Analiza zależności funkcyjnych i normalizacja tabel (dekompozycja do 3NF, BCNF, 4NF, 5NF) ==== {{:pl:dydaktyka:ztb:2012:projekty:fotodetektyw:erd2.jpg|}} 1NF - Warunki pierwszej postaci normalnej są spełnione: * Kaząda relacja opisuje jeden obiekt * Wartości atrybutów są elementarne * nie zawiera kolekcji * posiada klucz główny * kolejność wierszy może być dowolna 2NF - Wszystkie relacje spełniają pierwszą postać normalną i każda kolumna zależy od klucza głównego. 3NF - Trzecia postać normalna nie jest spełniona. Warunek mówiący o tym, że każda kolumna nienależąca do klucza głównego powinna być od niego bezpośrednio zależna nie jest spełniony przez tabelę RemoteAccessControlList - pole Permission. ==== 4. Projektowanie operacji na danych ==== Nasza aplikacja nie wykorzystuje predefiniowanych operacji na bazie danych. Wszystkie operacja wykonywane są mechanizm ORM - framework nHibernate. Do stworzenia map wykorzystana została nakładka Fluent nHibernate co pozwoliło na zastosowanie konwencji. Poniższy kod automatycznie mapuje wszystkie klasy implementujące interfejs IEntity i stosuje na nich konwencje określające nazwy kluczy. == Konfiguracja konwencji mapujących == var fluentConfig = Fluently.Configure() .Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString)) .Mappings( m=> m.AutoMappings.Add( AutoMap.Assemblies(AppDomain.CurrentDomain.GetAssemblies()) .Where(t => t.GetInterfaces().Contains(typeof(IEntity))) .IncludeBase() .Conventions.Add() .Conventions.Add() .Conventions.Add() .Conventions.Add(FluentNHibernate.Conventions.Helpers.DefaultLazy.Never()) .Override( x => x.IgnoreProperty(u => u.File)) .Override( x => x.Map(y => y.FacebookId).Unique()) .Override(x => x.Map(y => y.Username).Unique()) .Override(x => x.IgnoreProperty(y => y.ResponsesNum)) .Override(x => x.IgnoreProperty(y => y.CorrectResponsesNum)) .Override(x => x.IgnoreProperty(y => y.GamesNum)) )) .BuildConfiguration(); Ponieważ obiekty encji były również wykorzystywane do transferu danych pomiędzy frontendem a backendem. Domyślnie wyłączony został Lazy Loading. Jedynym przypadkiem kiedy doładowywanie obiektów jest konieczne jest związek pomiędzy Game i User. W tym celu zdefiniowaliśmy dodatkowe kryteria, umożliwiające tzw. Eager Loading _session.CreateCriteria("Game").SetFetchMode("User", FetchMode.Eager);