Relacja jeden do jeden a jeden do wielu

0

Witam

Mam takie pytanie. Jeśli posiadam bazę, w której są encje:

Wagon kolejowy oraz Skład kolejowy i w tabeli reprezentującej Wagon kolejowy mam pole id_skladu to:

  1. Rozpatrując to od strony wagonu jest to relacja 1 do 1 bo jeden wagon posiada jeden skład kolejowy (należy do pewnego składu).

  2. Rozpatrując to od strony składu kolejowego jest to relacja 1 do wielu bo jeden skład kolejowy może posiadać kilka wagonów.

Czy każda relacja 1 do 1 jest więc również jednocześnie relacją 1 do wielu?

0

Wyobraź sobie, że robisz relacje 1 do 1 dla użytkownika i jego numeru telefonu (w tabeli z numerem masz też jakieś inne dane). Tutaj w teorii nie masz 1 do wielu bo każdy użytkownik musi mieć indywidualny numer. W przypadku, gdy numer mógłby się powtarzać mogła to by być tabela jeden do wielu jednak była by ona nieoptymalizowana.

0

Jak sam mówisz, w skladzie może być wiele wagonów, a wagon może być w jednym składzie.
Tutaj odpowiednia jest relacja jeden do wielu.
Nie wiem czy dobrze rozumiem pytanie, ale nie.

0
anonimowy napisał(a):

Wyobraź sobie, że robisz relacje 1 do 1 dla użytkownika i jego numeru telefonu (w tabeli z numerem masz też jakieś inne dane). Tutaj w teorii nie masz 1 do wielu bo każdy użytkownik musi mieć indywidualny numer. W przypadku, gdy numer mógłby się powtarzać mogła to by być tabela jeden do wielu jednak była by ona nieoptymalizowana.

Pytanie jednak czy samo ustawienie OneToOne musi wymuszać fakt, że z dwóch stron element ma tylko JEDEN element powiązany?

Przykład z numerami telefonów jest taki sam jak z pociągami, bo oprócz osobistej komórki możesz posiadać:

  • numer telefonu stacjonarnego (i np. Twoja żona ma taki sam stacjonarny)
  • numer telefonu stacjonarnego w pracy (i np. Twój współpracownik ma taki sam stacjonarny)
  • numer telefonu komórkowego w aucie (wiele aut posiada wbudowany telefon) a np. autem jeździsz Ty i żona
0

jeden do jednego to jak sama nazwa wskazuja relacja jeden do jednego. odnośnie wiele numerów telefonów do użytkownika to relacja ManyToOne. wiele numerów do jednego użytkownika.

0

Czyli jeden do jednego to taka relacja w której również tamten drugi jeden ma tylko jednego, tak?

Pytanie jeszcze czy każdą jeden do jednego winna być jednokierunkowa? Tzn obojętnie w którym elemencie jestem mogę ten drugi z pary pobrać?

0
quechua napisał(a):

Czyli jeden do jednego to taka relacja w której również tamten drugi jeden ma tylko jednego, tak?
Ja bym powiedział, że jeden do jednego to taka relacja w której w tabeli A odpowiada tylko jeden rekord w tabeli B, a rekordowi w tabeli B odpowiada tylko jeden rekord a tabeli A. Bardzo często takie informacje siedzą w jednej tabeli. Wydzielenie może być dla celów np. wydajnościowych.

0
Mr.YaHooo napisał(a):
quechua napisał(a):

Czyli jeden do jednego to taka relacja w której również tamten drugi jeden ma tylko jednego, tak?
Ja bym powiedział, że jeden do jednego to taka relacja w której w tabeli A odpowiada tylko jeden rekord w tabeli B, a rekordowi w tabeli B odpowiada tylko jeden rekord a tabeli A. Bardzo często takie informacje siedzą w jednej tabeli. Wydzielenie może być dla celów np. wydajnościowych.

Tylko, że jeśli chodzi o budowę generalną tabel (kolumny) to jeden do jednego i wiele do jednego ma taką samą budowę, nieprawdaż?

Różnica polega na tym, że w relacji jeden do jednego COŚ PILNUJE BY dany JEDEN mógł należeć tylko do JEDNEGO. Pytanie "kto" to ma pilnować w ORM? Czy jest jakieś formalne ustalenie? Baza danych czy ORM?

0

@quechua jak bym powiedział, że 1:1 oraz 1:wielu nie muszą mieć takich samych struktur. Przy 1:1 wystarczy, że rekordy w obu tabelach będą miały takie samo ID (czy jak tam nazwiesz klucz główny), natomiast w relacji jeden do wielu musisz wprowadzić dodatkowe pole. Ba, w przypadku wiele do wielu musisz posłużyć się dodatkową tabelą.

Odnośnie tego co ma pilnować relacji, to w przypadku 1:1 takim jak ja zaproponowałem wystarczy, że będziesz miał klucz główny który jest unikalny, więc problemu nie ma. W innych przypadkach też można założyć indeks który będzie unikalny i sytuacja będzie analogiczna. Ja jestem zwolennikiem tej opcji gdzie baza sama z siebie trzyma spójność oraz poprawność powiązań pomiędzy rekordami. Dlatego wszędzie zakładam klucze obce które wymuszają taką spójność. W dodatku pozwalają na usunięcie kaskadowe rekordów po usunięciu "nadrzędnego" rekordu.

0
Mr.YaHooo napisał(a):

@quechua jak bym powiedział, że 1:1 oraz 1:wielu nie muszą mieć takich samych struktur. Przy 1:1 wystarczy, że rekordy w obu tabelach będą miały takie samo ID (czy jak tam nazwiesz klucz główny), natomiast w relacji jeden do wielu musisz wprowadzić dodatkowe pole. Ba, w przypadku wiele do wielu musisz posłużyć się dodatkową tabelą.

Ok rozjaśniłeś mi trochę jaśnie panie informację na szybko przeczytane w pociągu :P

Właściwie z tego punktu widzenia to błędem jest robienie relacji 1:1 w postaci:

tabela a:
id
nazwa
tabela b:
id
nazwa
a_id

powinno być:

tabela b:
a_id
nazwa

Kolejna "zagwozdka" to mamy relację jeden do wielu. Jest ona zaznaczana po stronie tego jednego. Np. Skład -> wagon, zaznaczam relacje przy składzie. Standardowo ORM udostępnia mi coś takiego Skład.Wagony.Add(Pociąg). A jak się nazywa takie coś, że również w Pociągu mogę ustawić Skład obiektowo czyli:

Pociag.Skład = objectSklad;

Czy to ma jakąś konkretną nazwę?

Bo relacji ManyToOne chyba zasadniczo nie ma?

0
quechua napisał(a):

Pytanie jednak czy samo ustawienie OneToOne musi wymuszać fakt, że z dwóch stron element ma tylko JEDEN element powiązany?

Oczywiście, inaczej by to nie miało sensu.

Mr.YaHooo napisał(a):

@quechua jak bym powiedział, że 1:1 oraz 1:wielu nie muszą mieć takich samych struktur. Przy 1:1 wystarczy, że rekordy w obu tabelach będą miały takie samo ID (czy jak tam nazwiesz klucz główny)

A co jeśli związek jest opcjonalny?
Ty piszesz o rozbijaniu tabeli na dwie, nie o związkach 1:1.

Ja jestem zwolennikiem tej opcji gdzie baza sama z siebie trzyma spójność oraz poprawność powiązań pomiędzy rekordami. Dlatego wszędzie zakładam klucze obce które wymuszają taką spójność. W dodatku pozwalają na usunięcie kaskadowe rekordów po usunięciu "nadrzędnego" rekordu.

Świetny pomysł na przypadkowe skasowanie całej bazy albo spędzenie dziesiątek godzin na debugowaniu.

Właściwie z tego punktu widzenia to błędem jest robienie relacji 1:1 w postaci:

tabela a:
id
nazwa
tabela b:
id
nazwa
a_id

powinno być:

tabela b:
a_id
nazwa

Nie, nie powinno tak być. Klucz obcy powinien być. Jeśli masz jedną kolumnę ID w obu tabelach, to masz jedną tabelę rozbitą na dwie, a nie związek 1:1.

Pociag.Skład = objectSklad;

Czy to ma jakąś konkretną nazwę?

To się nazywa ustawienie wartości właściwości obiektu.

Pytanie tylko, czemu na poziomie obiektowym chcesz mieć cykliczne referencje?

Powtarzam jeszcze raz - nie ma czegoś takiego jak "relacja 1:1" ani "relacja 1:N".
Relacje istnieją w relacyjnych bazach danych, i są zbiorami krotek definiowanymi przez te same atrybuty (schemat), w efekcie czego fizycznie wyglądają jak tabele.
Natomiast krotności związków (1:1, 1:N, M:N) istnieją w modelach związków-encji, które to dopiero są transformowane na model relacyjny podczas implementacji bazy danych. Krotność taka w bazie relacyjnej przyjmuje najczęściej postać klucza obcego.

O tym co to są relacyjne bazy danych możecie przeczytać tutaj: http://osilek.mimuw.edu.pl/index.php?title=Bazy_danych/Wyk%C5%82ad_2
O modelowaniu związków encji tutaj: http://osilek.mimuw.edu.pl/index.php?title=Bazy_danych/Wyk%C5%82ad_3
A o transformowaniu drugiego na pierwsze tutaj: http://osilek.mimuw.edu.pl/index.php?title=Bazy_danych/Wyk%C5%82ad_4

0
somekind napisał(a):

A co jeśli związek jest opcjonalny?
Ty piszesz o rozbijaniu tabeli na dwie, nie o związkach 1:1.
Racja, zagalopowałem się.

Świetny pomysł na przypadkowe skasowanie całej bazy albo spędzenie dziesiątek godzin na debugowaniu.
Jeśli nie ma się dokumentacji do bazy to faktycznie można narobić bałaganu. Ale weź przypadek programu w którym masz faktury. Wtedy musisz mieć 2 tabele. Jedna to faktury druga to pozycje faktur. Naturalnym jest ustawienie klucza obcego z kasowaniem kaskadowym po to aby przy usuwaniu faktury usunąć również jej pozycje, wiec nie wiem jak można tym skasować całą bazę. A po co mi wchodzić podczas debugowania do procedury usuwającej pozycje faktury skoro to ma działać automatem? Ja traktuję fakturę jako całość i tyle.

Nie, nie powinno tak być. Klucz obcy powinien być. Jeśli masz jedną kolumnę ID w obu tabelach, to masz jedną tabelę rozbitą na dwie, a nie związek 1:1.
Tak, ale wtedy też można a nawet warto założyć klucz obcy na pole ID pomiędzy dwoma tabelami.

Powtarzam jeszcze raz - nie ma czegoś takiego jak "relacja 1:1" ani "relacja 1:N".
Niby tak, jednak nawet wykładowcy stosują takie określenia.

A wracając do związku 1:1 to faktycznie dodaje się wtedy w którejś tabeli pole na które zakłada się klucz zewnętrzny i już. Przykładowo:

Akwizytorzy:
ID           int,
IMIE         varchar(30),
NAZWISKO     varchar(30)

Kontrahenci:
ID           int,
NAZWA        varchar(300),
NIP          varchar(30),
AKWOZYTOR_ID int

I wtedy na pole AKWIZYTOR_ID zakładamy klucz zewnętrzny i już. Oczywiście tu nie ma co ustawiać kaskadowego usuwania, bo wtedy faktycznie można usunąć połowę rekordów.

0
Mr.YaHooo napisał(a):

A wracając do związku 1:1 to faktycznie dodaje się wtedy w którejś tabeli pole na które zakłada się klucz zewnętrzny i już. Przykładowo:

Akwizytorzy:
ID           int,
IMIE         varchar(30),
NAZWISKO     varchar(30)

Kontrahenci:
ID           int,
NAZWA        varchar(300),
NIP          varchar(30),
AKWOZYTOR_ID int

I wtedy na pole AKWIZYTOR_ID zakładamy klucz zewnętrzny i już. Oczywiście tu nie ma co ustawiać kaskadowego usuwania, bo wtedy faktycznie można usunąć połowę rekordów.

Jeśli dodatkowo nie założysz na "AKWIZYTOR_ID" unique to IMO założyłeś relację 1 do wielu a nie 1:1.

0
Mr.YaHooo napisał(a):

Ale weź przypadek programu w którym masz faktury. Wtedy musisz mieć 2 tabele. Jedna to faktury druga to pozycje faktur. Naturalnym jest ustawienie klucza obcego z kasowaniem kaskadowym po to aby przy usuwaniu faktury usunąć również jej pozycje, wiec nie wiem jak można tym skasować całą bazę. A po co mi wchodzić podczas debugowania do procedury usuwającej pozycje faktury skoro to ma działać automatem? Ja traktuję fakturę jako całość i tyle.

No w tym przypadku jest to bezpieczne, gorzej jakby ustawić kaskadowe usuwanie między pozycjami faktury, a produktami - a niektórzy artyści baz danych tak potrafią. ;)
Niemniej jednak - po co w ogóle usuwać? Soft delete wystarczy.

Niby tak, jednak nawet wykładowcy stosują takie określenia.

No to należy ich natychmiast przestać słuchać.

I wtedy na pole AKWIZYTOR_ID zakładamy klucz zewnętrzny i już. Oczywiście tu nie ma co ustawiać kaskadowego usuwania, bo wtedy faktycznie można usunąć połowę rekordów.

Pełna zgoda.

quechua napisał(a):

Jeśli dodatkowo nie założysz na "AKWIZYTOR_ID" unique to IMO założyłeś relację 1 do wielu a nie 1:1.

Nie.
Tutaj szczegółowa rozpiska, jaki związek transformuje się na jaki model relacyjny: http://osilek.mimuw.edu.pl/index.php?title=BD-2st-1.2-w04.tresc-1.1-Slajd7

0
somekind napisał(a):

No w tym przypadku jest to bezpieczne, gorzej jakby ustawić kaskadowe usuwanie między pozycjami faktury, a produktami - a niektórzy artyści baz danych tak potrafią. ;)
Jeśli ktoś tak robi to jednak sądzę, że powinien zmienić pracę... ;)

somekind napisał(a):

Niemniej jednak - po co w ogóle usuwać? Soft delete wystarczy.
Jak dla mnie to jest trochę uciążliwe. Wtedy zazwyczaj plącze się jakaś dodatkowa klauzula podczas pisania zapytań SQL'owych. Niby zawsze można korzystać z widoków i na nich operować, jednak zawsze można się pomylić. Poza tym co jeśli masz unikalny klucz dla np. symbolu towaru? Wtedy po ustawieniu flagi skasowania nie da się wprowadzić drugi raz tego samego symbolu. Podobnie z numerem dokumentu czy faktury. Dlatego ja u siebie jestem zmuszony kasować jak user kliknie klawisz Del na klawiaturze.

0
Mr.YaHooo napisał(a):

Jak dla mnie to jest trochę uciążliwe. Wtedy zazwyczaj plącze się jakaś dodatkowa klauzula podczas pisania zapytań SQL'owych. Niby zawsze można korzystać z widoków i na nich operować, jednak zawsze można się pomylić.

Różnica naszych zdań wynika zapewne z tego, że dla mnie pisanie kodu SQL jest ostatecznością, którą stosuję tylko ze względu na wydajność albo brak innych możliwości. Sam soft delete względnie łatwo obsłużyć automatycznie przez ORM.

Poza tym co jeśli masz unikalny klucz dla np. symbolu towaru? Wtedy po ustawieniu flagi skasowania nie da się wprowadzić drugi raz tego samego symbolu. Podobnie z numerem dokumentu czy faktury. Dlatego ja u siebie jestem zmuszony kasować jak user kliknie klawisz Del na klawiaturze.

No, ale to już jest błąd innego rodzaju - użycie naturalnego klucza głównego. Kod, numer faktury, PESEL - to nie są wartości, które nadają się na PK. Klucz powinien być sztuczny.

0
somekind napisał(a):

Różnica naszych zdań wynika zapewne z tego, że dla mnie pisanie kodu SQL jest ostatecznością, którą stosuję tylko ze względu na wydajność albo brak innych możliwości. Sam soft delete względnie łatwo obsłużyć automatycznie przez ORM.
Niestety tak. Ja z pewnych względów muszę pracować pisząc polecenia SQL. Zastosowanie ORM w moim systemie jednak wiązałoby się z przepisaniem wielu modułów i niestety nie ma na to czasu.

No, ale to już jest błąd innego rodzaju - użycie naturalnego klucza głównego. Kod, numer faktury, PESEL - to nie są wartości, które nadają się na PK. Klucz powinien być sztuczny.
Oczywiście, jako klucza głównego używam sztucznie nadawanego ID. Dodatkowo na pewne rzeczy jak symbole towarów, czy numer dokumentu zakładam klucze unikalne. Po prostu nie może się zdarzyć aby w systemie istniały dwie faktury o tym samym numerze. Co więcej numeracja jest w ramach typu dokumentu, magazynu oraz roku wyciągniętego z daty dokumentu. Taki klucz pozwala mi uniknąć w najprostszy sposób sytuacji gdzie mamy zdublowany numer. Jak ktoś nawet wpisze w systemie numer dokumentu który już był wykorzystany, to podczas zapisywania do bazy będzie rzucony wyjątek który mogę obsłużyć i wyświetlić okno z informacją, że taki numer już istnieje. Inaczej nie byłoby tak łatwo.

0
somekind napisał(a):
quechua napisał(a):

Jeśli dodatkowo nie założysz na "AKWIZYTOR_ID" unique to IMO założyłeś relację 1 do wielu a nie 1:1.

Nie.
Tutaj szczegółowa rozpiska, jaki związek transformuje się na jaki model relacyjny: http://osilek.mimuw.edu.pl/index.php?title=BD-2st-1.2-w04.tresc-1.1-Slajd7

Oczywiście, że TAK, bo będzie istniała możliwość dodania wielu samochodów do jednego pracownika. Opieram się dokładnie na tym linku:

http://osilek.mimuw.edu.pl/index.php?title=BD-2st-1.2-w04.tresc-1.1-Slajd8

Nic tam nie jest napisane o wymuszeniu Unique na kolumnie IdPracownika w tablicy Samochody. A więc przytoczony przykład z UW zawiera błąd.

Przecież ten związek encji wygląda dokładnie tak jak tu w przypadku 1:M

http://osilek.mimuw.edu.pl/index.php?title=BD-2st-1.2-w04.tresc-1.1-Slajd12

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