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 |
DataObject | OriginalFilename | 3 | NULL | YES | nvarchar |
DataObject | Path | 2 | NULL | YES | nvarchar |
FacebookUser | FacebookId | 2 | NULL | YES | bigint |
FacebookUser | User_id | 1 | NULL | NO | int |
Game | Date | 4 | NULL | YES | datetime |
Game | Description | 3 | NULL | YES | nvarchar |
Game | GameId | 1 | NULL | NO | int |
Game | Name | 2 | NULL | YES | nvarchar |
Game | Photo_id | 5 | NULL | YES | int |
Game | Resolved | 7 | NULL | YES | bit |
Game | User_id | 6 | NULL | YES | int |
GameAccessControlList | Game_id | 4 | NULL | YES | int |
GameAccessControlList | GameAccessControlListId | 1 | NULL | NO | int |
GameAccessControlList | Permission | 2 | NULL | YES | nvarchar |
GameAccessControlList | User_id | 3 | NULL | YES | int |
LocalUser | Password | 2 | NULL | YES | nvarchar |
LocalUser | User_id | 1 | NULL | NO | int |
LocalUser | Username | 3 | NULL | YES | nvarchar |
Response | Comment | 4 | NULL | YES | nvarchar |
Response | Correctness | 5 | NULL | YES | bit |
Response | Date | 2 | NULL | YES | datetime |
Response | Game_id | 6 | NULL | YES | int |
Response | Photo_id | 9 | NULL | YES | int |
Response | ResponseId | 1 | NULL | NO | int |
Response | User_id | 8 | NULL | YES | int |
ResponseAccessControlList | Permission | 2 | NULL | YES | nvarchar |
ResponseAccessControlList | Response_id | 4 | NULL | YES | int |
ResponseAccessControlList | ResponseAccessControlListId | 1 | NULL | NO | int |
ResponseAccessControlList | User_id | 3 | NULL | YES | int |
Role | Name | 2 | NULL | YES | nvarchar |
Role | RoleId | 1 | NULL | NO | int |
RolesToUsers | Role_id | 1 | NULL | NO | int |
RolesToUsers | User_id | 2 | NULL | NO | int |
User | Email | 3 | NULL | YES | nvarchar |
User | UserId | 1 | NULL | NO | int |
User | Username | 2 | NULL | YES | nvarchar |
NULL | NULL | NULL | NULL | NULL | NULL |
3. Analiza zależności funkcyjnych i normalizacja tabel (dekompozycja do 3NF, BCNF, 4NF, 5NF)
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<User>()
.Conventions.Add<PrimaryKeyConvention>()
.Conventions.Add<CustomForeignKeyConvention>()
.Conventions.Add<ForeignKeyConstraintNameConvention>()
.Conventions.Add(FluentNHibernate.Conventions.Helpers.DefaultLazy.Never())
.Override<DataObject>( x => x.IgnoreProperty(u => u.File))
.Override<FacebookUser>( x => x.Map(y => y.FacebookId).Unique())
.Override<LocalUser>(x => x.Map(y => y.Username).Unique())
.Override<User>(x => x.IgnoreProperty(y => y.ResponsesNum))
.Override<User>(x => x.IgnoreProperty(y => y.CorrectResponsesNum))
.Override<User>(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);