Struktura bazy danych aplikacji - opinie i porady

1

Witam,

Wraz z kolegą zdecydowaliśmy się na projekt w języku C# z bazą danych MySQL lub SQL Server - nad tym jeszcze myślimy, choć nie ma to w tej chwili większego znaczenia.
Stworzyliśmy sobie założenia do aplikacji i przedstawię Wam je poniżej wypunktowane:
2. Założenia
2.1. Aplikacja desktopowa – WPF

Użytkownikiem aplikacji desktopowej jest osoba nadzorująca pracę pracowników w firmie, zwana dalej „Pracodawcą”.
• Logowanie do systemu poprzez login i hasło.
• Wylogowywanie z systemu.
• Pracodawca ma możliwość tworzenia, edycji, usuwania oraz nadawania uprawnień kont pracownikom dla aplikacji mobilnej.
• Każdy z pracodawców posiada swoich pracowników, którzy pod niego podlegają.
• Dostępna lista pracowników wraz ze statusami (statusy to flaga czy jest online czy offline).
• Możliwość podglądu lokalizacji wybranych pracowników na mapie (współrzędne GPS).
• Możliwość komunikacji tekstowej z jednym, bądź wszystkimi pracownikami (czat z z pojedyńczą osobą lub ogólnodostępny).
• Możliwość nadzoru wysyłanych zgłoszeń przez pracowników (pracownicy wysyłają zgłoszenia typu: rozpocząłem pracę, zakończyłem pracę, itp.).

2.2. Aplikacja mobilna – WP, Android, iOS

Użytkownikami aplikacji mobilnej są pracownicy, zwani dalej „Pracownikami”.
• Logowanie do systemu poprzez login i hasło.
• Wylogowywanie z systemu.
• Pracownik ma możliwość zmiany hasła.
• Możliwość wysyłania zgłoszeń wraz z uwagami:
o podjęcie pracy,
o zakończenie pracy.
o ...
• Możliwość komunikacji tekstowej z jednym, bądź wszystkimi pracownikami.
• W przypadku gdy jest to konto pracodawcy to ma on możliwość podglądu lokalizacji wybranych pracowników na mapie.
• Dostępna lista pracowników wraz ze statusami.

2.3. WebService – WCF

WebService jest „pośrednikiem” pomiędzy aplikacją desktopową, mobilną, a bazą danych.
• WebService łączy się bezpośrednio z aplikacją mobilną, desktopową i bazą danych.
• Realizuje funkcjonalności wypisane w punkcie 2.1. oraz 2.2.

Pytanie moje tyczy się struktury bazy danych (diagramu ERD). Stworzyliśmy go na podstawie właśnie powyższych założeń. Przedstawiam go poniżej:
ERD.PNG

Bardzo byśmy oczekiwali konstruktywnej krytyki, wszelkich porad co jest źle, a co dobrze :)
Pozdrawiam serdecznie.

2

Osobiście nie ma się do czego przyczepić. Można by stworzyć jedna tabelę z informacjami odnośnie pracowników i pracodawców zamiast dwóch. Informacje się dublują różni się tylko klucz obcy. Może lepiej lokalizację przechowywać jako współrzędne x y zamiast varchar, no ale to kwestia tego jak ma być wyświetlana ta wartość w programach. W systemie wielu pracodawców może należeć do jednej firmy, pytanie czy taki ma być system ? Czy nie lepiej utożsamić pracodawcę z firmą. To znaczy zamiast pracodawcy dać konto firmy. No, ale to zależy od tego jak to widzicie.

2

Ja już kiedyś o tym pisałem i nie jestem zwolennikiem dzielenia login/hasło w jednej tabeli imię/nazwisko w drugiej to po pierwsze po drugie masz dwie tabele z userami gdzie jest login hasło. Przy logowaniu będziesz musiał robić kombinacje aby zapewnić unikalność danych między dwoma tabelami ponieważ jak będzie login a i hasło a jako pracownik i ten sam login z tym samym haslem jako pracodawca to w momencie jednego formularza nie będziesz w stanie zdecydować kto się zalogował (no chyba, że po stronie interfejsu użytkownika zrobisz dwa oddzielne formularze dla pracowników i pracodawców). Ja bym to uprościł. Wrzuciłbym imie/nazwisko do tabeli users w niej byli by pracownicy i pracodawcy oraz dorobił flagę, która określi czy dany user jest pracownikiem czy pracodawcą. Dzięki temu na login dajesz Unique constraint i masz spokój z unikalnością loginów. Nie musisz też dbać o różne formularze logowania. Co za tym idzie upraszcza Ci się tabela messages bo miałbyś user_from i user_to nie mówiąc już o oczopląsie employeers employees.

Kolejna rzecz to lokalizacje. Z doświadczenia zawodowego powiem Ci, że lokalizacje lepiej trzymać oddzielnie Latitude i Longitude jako liczbę nie musisz potem przy np przekazywaniu do google maps robić konwersji itd. Ponadto w interfejsie jak będziesz miał pole numeryczne to łatwiej zabezpieczyć przed wpisaniem np ABC - komponenty same to załatwiają.

Ostatnia uwaga nie wiem do czego Ci pole Role ale jeśli ma ono działać na zasadzie kontroli uprawnień to lepiej zrobić IDRoli + oddzielną tabelę z rolami (id int, nazwa varchar) + oddzielną tabelę z Uprawnieniami (tutaj dowolność co potrzebujesz) + tabela spięcia rola + uprawnienie. Chyba, że w samym interfejsie będziesz robić warunki

 if rola <> "Admin" then Exit;

To tyle jeśli o mnie chodzi ;)

2
XardasLord napisał(a):

Bardzo byśmy oczekiwali konstruktywnej krytyki, wszelkich porad co jest źle, a co dobrze :)
Pozdrawiam serdecznie.

  1. Employer ma chyba jedno e.
  2. Nie myślcie o MySQL, lepszy Postgres.
  3. Do danych geograficznych istnieją specjalne typy.
  4. Skoro chcecie pisać aplikację, to zróbcie diagram klas, a nie ERD.
woolfik napisał(a):

Ja bym to uprościł. Wrzuciłbym imie/nazwisko do tabeli users w niej byli by pracownicy i pracodawcy oraz dorobił flagę, która określi czy dany user jest pracownikiem czy pracodawcą.

Koncepcja słuszna.
A zarazem doskonały przykład problemu wynikającego z prehistorycznego podejścia do tworzenia aplikacji ze złej strony, czyli od bazy danych.
Gdyby zacząć od diagramu klas, to narysowałoby się klasę bazową User, dziedziczące z niej Employee i Employer, i tyle. Sposób przechowywania hierarchii klas w bazie, to kwestia konfiguracji ORMa.

Ostatnia uwaga nie wiem do czego Ci pole Role ale jeśli ma ono działać na zasadzie kontroli uprawnień to lepiej zrobić IDRoli + oddzielną tabelę z rolami (id int, nazwa varchar) + oddzielną tabelę z Uprawnieniami (tutaj dowolność co potrzebujesz) + tabela spięcia rola + uprawnienie. Chyba, że w samym interfejsie będziesz robić warunki

 if rola <> "Admin" then Exit;

O ile nie potrzebujemy przechowywać dodatkowych informacji o rolach, to wystarczy, żeby Role były flagowalnym enumem (1,2,4, itd.). Unikniemy w ten sposób bezsensownego joinowania dwóch tabel.

0
somekind napisał(a):

Nie myślcie o MySQL, lepszy Postgres.

A dlaczego uważasz, że Postgres będzie lepszym rozwiązaniem niż MySql?

0
woolfik napisał(a):

Ja bym to uprościł. Wrzuciłbym imie/nazwisko do tabeli users w niej byli by pracownicy i pracodawcy oraz dorobił flagę, która określi czy dany user jest pracownikiem czy pracodawcą. Dzięki temu na login dajesz Unique constraint i masz spokój z unikalnością loginów. Nie musisz też dbać o różne formularze logowania. Co za tym idzie upraszcza Ci się tabela messages bo miałbyś user_from i user_to nie mówiąc już o oczopląsie employeers employees.

Okej wszystko rozumiem i tak rzeczywiście byłoby lepiej trzymać to w bazie, aczkolwiek problem pojawia wtedy, gdy będę chciał przypisać pracowników do pracodawców, bo w jaki sposób to zrobić przy pomocy jednej tabeli Users?

Koncepcja słuszna.
A zarazem doskonały przykład problemu wynikającego z prehistorycznego podejścia do tworzenia aplikacji ze złej strony, czyli od bazy danych.
Gdyby zacząć od diagramu klas, to narysowałoby się klasę bazową User, dziedziczące z niej Employee i Employer, i tyle. Sposób przechowywania hierarchii klas w bazie, to kwestia konfiguracji ORMa.

Przyzwyczajeni jesteśmy do złych nawyków w takim razie, skoro zaczynamy od bazy danych, dzięki za takie spostrzeżenia - tego właśnie potrzeba nam na przyszłość :) Czyli rozumiem, że faktycznie klasa Users będzie istniała fizycznie w aplikacji, natomiast zostanie pominięta w bazie danych przy konfiguracji ORMa? Zostaną tylko dziedziczące po niej Employer i Employee.

1
Rejencina napisał(a):

A dlaczego uważasz, że Postgres będzie lepszym rozwiązaniem niż MySql?

Bo jest dojrzalszy i bardziej funkcjonalny.

XardasLord napisał(a):

Czyli rozumiem, że faktycznie klasa Users będzie istniała fizycznie w aplikacji, natomiast zostanie pominięta w bazie danych przy konfiguracji ORMa? Zostaną tylko dziedziczące po niej Employer i Employee.

W relacyjnych bazach danych w ogóle nigdy nie ma klas... Zakładam, że pytasz o to, czy w bazie będzie tabela "Users"? To zależy od wybranego rodzaju mapowania hierarchii klas na tabele, generalnie są trzy możliwości:

  1. TPH - cała hierarchia w jednej tabeli, kolumny specyficzne dla klas potomnych są nullowalne i ustawiane tylko dla obiektów tych klas.
  2. TPT - klasa bazowa w jednej tabeli, właściwości specyficzne dla każdej klasy potomnej w oddzielnej tabeli, połączonej z bazową kluczem obcym.
  3. TPC - każda klasa w oddzielnej tabeli.

Każdy ma swoje wady i zalety, które trzeba rozważyć przed użyciem.

1
XardasLord napisał(a):

Okej wszystko rozumiem i tak rzeczywiście byłoby lepiej trzymać to w bazie, aczkolwiek problem pojawia wtedy, gdy będę chciał przypisać pracowników do pracodawców, bo w jaki sposób to zrobić przy pomocy jednej tabeli Users?

Możesz przy pomocy jednej tabeli np dodając do tabeli users pole IDPracodawcy - ale jest to moim zdaniem w tym przypadku kiepskie rozwiązanie bo masz relację tylko 1 do wielu ponadto musisz zrobić check kontrolujący czy IDPracodawcy zgadza się z IDUsera i polem okreslającym pracodawce (flaga o której pisałem wcześnie) ponadto jak będziesz chciał zrobić zapytanie określające strukturę pracodawca->kierownik->pracownik itd to musisz się trochę nagimnastykować tworząc takiego selecta. Lepiej zrobić oddzielną tabelę gdzie masz idpracodawcy i idpracownika. To pozwoli Ci również na uzyskanie sytuacji gdy jeden pracownik pracuje u kilku pracodawców bo możesz zrobić relację wiele do wielu

1 użytkowników online, w tym zalogowanych: 0, gości: 1