Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
1:1 Beziehung von einer Tabelle zu mehreren anderen
Paschulke
myCSharp.de - Member



Dabei seit:
Beiträge: 63

Themenstarter:

1:1 Beziehung von einer Tabelle zu mehreren anderen

beantworten | zitieren | melden

verwendetes Datenbanksystem: SQL Server

Hallo,

ich arbeite an einer Anwendung zur Verwaltung von Personendaten.
- Darin gibt es eine zentrale Tabelle namens "Person"
- Zur Personen-Tabelle existieren eine Reihe von Detailtabellen mit PersonId als Fremdschlüssel (z. B. Anschrift)
- Jede Tabelle (also hier Person und Anschrift) hat eine 1:1 Beziehung zu einer "Vorgangstabelle"

Zum Sinn der Vorgangstabelle:
Beim Öffnen einer Person soll ein "Vorgangsbaum" angezeigt werden, der dem Benutzer eine schnelle Übersicht der Daten zu dieser Person gibt. Aus diesem Grund haben wir die "Vorgangstabelle" erstellt, die im Wesentlichen aus der PersonId, und einer Caption für den Vorgangsbaum besteht. So kann der Baum mit einem Select auf einer Tabelle erzeugt werden. Ich muss allerdings über die Vorgangstabelle auch an die Id des verbundenen Datensatzes kommen, damit ein Doppelklick den Datensatz zur Bearbeitung öffnet. Das könnte mir denke ich das EF durch das Mapping liefern, oder?

Fragen:
1. Wie löst man eine solche 1:1 Beziehung am Besten, wenn man möglichst auch die referentielle Integrität sicher stellen möchte. Geht das überhaupt? Oder kann man gar nicht gewährleisten, dass ein Vorgangsdatensatz irgendwann z. B. ohne zugehörigen Personendatensatz existiert?
2. Wie würde das Mapping im Entity Framework aussehen?
3. Die Vorgangstabelle hat ja auch eine PersonId. Wenn ich eine Person anlege, bekomme ich spätestens hier Schwierigkeiten, weil ein Zirkelbezug existiert. Kann man so etwas auch irgendwie geschickter lösen? Notfalls müsste ich nachträglich ein Update auf das dann notwendigerweise "nullable" Feld PersonId machen...

Viele Grüße
Paschulke
private Nachricht | Beiträge des Benutzers
Diräkt
myCSharp.de - Member



Dabei seit:
Beiträge: 619
Herkunft: Schweiz

beantworten | zitieren | melden

Hallo Paschulke

- Jede Tabelle (also hier Person und Anschrift) hat eine 1:1 Beziehung zu einer "Vorgangstabelle"

... Ich habe eigentlich noch nie ein vernünftigen Grund gesehen, wesshalb man nicht gleich auf 1:1 Relations verzichtet und die Spalten direkt in die Tabelle packt ....

1. Wie löst man eine solche 1:1 Beziehung am Besten, wenn man möglichst auch die referentielle Integrität sicher stellen möchte. Geht das überhaupt? Oder kann man gar nicht gewährleisten, dass ein Vorgangsdatensatz irgendwann z. B. ohne zugehörigen Personendatensatz existiert?

Wenn alles 1:1 in der gleichen Tabelle ist, hast du das Problem gar nicht

Bei der refrentiellen Integrität kannst ja wählen (Update ; Delete weitergabe ... )

2. Wie würde das Mapping im Entity Framework aussehen?

Sowie du es in der DB abgebildet hast :-) Du kriegst halt ein NavigationProperty zu Deiner "Stammtabelle".

3. Die Vorgangstabelle hat ja auch eine PersonId. Wenn ich eine Person anlege, bekomme ich spätestens hier Schwierigkeiten, weil ein Zirkelbezug existiert. Kann man so etwas auch irgendwie geschickter lösen? Notfalls müsste ich nachträglich ein Update auf das dann notwendigerweise "nullable" Feld PersonId machen...

Siehe mein erster Kommentar :-)


Beste Grüsse

Diräkt
private Nachricht | Beiträge des Benutzers
Paschulke
myCSharp.de - Member



Dabei seit:
Beiträge: 63

Themenstarter:

beantworten | zitieren | melden

Zitat von Diräkt
... Ich habe eigentlich noch nie ein vernünftigen Grund gesehen, wesshalb man nicht gleich auf 1:1 Relations verzichtet und die Spalten direkt in die Tabelle packt ....
Genau diesen Kommentar hatte ich erwartet und deshalb den Sinn der Vorgangstabelle erläutert.
Wie baust Du dann den Vorgangsbaum performant und wartbar auf?
private Nachricht | Beiträge des Benutzers
Diräkt
myCSharp.de - Member



Dabei seit:
Beiträge: 619
Herkunft: Schweiz

beantworten | zitieren | melden

Hallo Paschulke

Vielleicht versteh ich deine "Vorgangstabelle" einfach nicht ;-)

Wie wäre es mit:
=> Vorgangstabelle (M:N) -> Person

Vorgangstabelle
Id
Caption

Person
....

VorgangPerson
Id
VorgangId
PersionId



Beste Grüsse

Diräkt
private Nachricht | Beiträge des Benutzers
Paschulke
myCSharp.de - Member



Dabei seit:
Beiträge: 63

Themenstarter:

beantworten | zitieren | melden

Eine 1:1-Beziehung in eine m:n-Beziehung umwandeln...? Klingt nicht gerade vernünftig. Aber ich muss zugeben, dass mir zumindest der Gedanke auch schon einmal kam... Sinnvoll ist das aber denke ich nicht.

Ich versuche einmal ganz grundsätzlich das Problem zu schildern:
Der Anwender wählt über eine Suchmaske eine Person aus. Es öffnet sich ein Fenster zur Bearbeitung dieser Person. Hier wird auf der linken Seite ein Vorgangsbaum angezeigt, der dem Benutzer die Möglichkeit gibt, Detaildaten zur gewählten Person zu berabeiten.

Das sieht in etwas wie folgt aus:
- Adressen
-- Postanschrift
-- Hauptanschrift
- Kommunikationsdaten
-- E-Mail
-- Telefon
- Dienstverhältnisse
-- 01.01.2008 - 31.12.2009
-- 01.01.2010 - offen
- Fortbildungen
-- 01.01.2008 - 14.01.2008
-- ...

Nach diesem Beispiel gäbe es die Tabellen "Adresse", Kommunikation", "Dienstverhältnis", "Fortbildung". Jede Tabelle enthält also Detaildaten zu einer Person.
Insgesamt gibt es ca. 90 solcher Detailtabellen!

Wenn das Personenfenster geöffnet wird, muss der Vorgangsbaum erstellt werden. WIE?
Ich müsste jede Detailtabelle nach Einträgen zu der Person durchsuchen und die entsprechenden Daten zum Baum hinzufügen. Das ist erstens nicht performant und zweitens schlecht wartbar.
Deshalb die Idee eine "Vorgangstabelle" zu erstellen. Beim Speichern eines Datensatzes wird ein Eintrag in dieser Tabelle erzeugt. Wesentliche Spalten: PersId, Vorgangsbaumbeschriftung, IdentifierDerDetailtabelle

Ein Doppelklick auf einen Eintrag soll den Datensatz zur Bearbeitung öffnen. Deshalb müsste evtl. (falls EF das nicht anders liefert) die Id des "Stammdatensatzes" zusätzlich abgespeichert werden.

Macht das den Sinn vielleicht etwas deutlicher? Ich hoffe... ;-)
private Nachricht | Beiträge des Benutzers
san-software
myCSharp.de - Member



Dabei seit:
Beiträge: 96

beantworten | zitieren | melden

und genau an den 90 tabellen liegt Dein Knackpunkt.
So wie Diräkt schon geschrieben hat, solltest Du keine 1:1-Beziehungen aufbauen.
Adressdaten und Kommunikationsdaten sind pro Person nur einmal vorhanden, und gehören daher in die Personentabelle.

Wenn Du das mit allen solchenTabellen machst, dann hast Du am Schluß keine 90 Tabellen sondern bedeutend weniger.
Zitat
Ich müsste jede Detailtabelle nach Einträgen zu der Person durchsuchen und die entsprechenden Daten zum Baum hinzufügen. Das ist erstens nicht performant und zweitens schlecht wartbar.

Mußt Du nicht, denn mit einer entsprechenden SQL-Anweisung gibt Dir Deine Datenbank nämlich dann schnell alle benötigten Daten zurück.
private Nachricht | Beiträge des Benutzers
Paschulke
myCSharp.de - Member



Dabei seit:
Beiträge: 63

Themenstarter:

beantworten | zitieren | melden

Zitat von san-software
Adressdaten und Kommunikationsdaten sind pro Person nur einmal vorhanden, und gehören daher in die Personentabelle.
Nein, sind sie nicht. Eine Person kann mehrere Adressen haben. Ich ahne worauf Du hinaus willst. Ich soll eine Spalte "Postanschrift", eine Spalte "Hausanschrift"... erstellen. Und eine Spalte "E-Mail", eine Spalte "Mobil" usw. Ok, bei diesen beiden Tabellen ginge das. Vielleicht waren sie als Beispiel nicht gut. Ich hatte sie gewählt, weil sie auch für nicht im der Fachlichkeit steckende Personen leicht verständlich sind. Dachte ich...

In den meisten Fällen geht es um solche Dinge wie Fortbildungen, Krankheiten usw. Sie haben i. d. R. ein Beginn und ein Ende und sind beliebig oft vorhanden. Ich kann sie nicht in die Personentabelle integrieren. Zumindest wüsste ich nicht wie...?
private Nachricht | Beiträge des Benutzers
Khalid
myCSharp.de - Experte

Avatar #avatar-2534.gif


Dabei seit:
Beiträge: 3627
Herkunft: Hannover

beantworten | zitieren | melden

Hi,

schau dir mal das EAV Datenbankmodell an. Damit kann man sowas von der Datenbank Seite her recht einfach abbilden, von der Reporting Seite her wird es allerdings komplizierter.

Bist du auf den SQL Server angewiesen, oder kannst du ggf. umstellen? Wenn ja, ist dies ein typischer Fall für NoSQL (z.B. MobgoDB).

Gruß
Khalid
"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)
private Nachricht | Beiträge des Benutzers
Diräkt
myCSharp.de - Member



Dabei seit:
Beiträge: 619
Herkunft: Schweiz

beantworten | zitieren | melden

Hallo Paschulke
Zitat
Nein, sind sie nicht. Eine Person kann mehrere Adressen haben.
Zitat
Jede Tabelle (also hier Person und Anschrift) hat eine 1:1 Beziehung zu einer "Vorgangstabelle"

Diese zwei Zitate wiedersprechen sich irgendwie ?!

Dann sind alles 1:N Verknüpfungen zur Personentabelle.
Je nach dem wie die einzelnen Tabellen aussehen könntest hier sicher einiges zusammenfassen durch Vererbung etc... (was mit EF ja auch funktioniert ;))


Beste Grüsse

Diräkt
private Nachricht | Beiträge des Benutzers
Paschulke
myCSharp.de - Member



Dabei seit:
Beiträge: 63

Themenstarter:

beantworten | zitieren | melden

Zitat von Diräkt
Zitat
Nein, sind sie nicht. Eine Person kann mehrere Adressen haben.
Zitat
Jede Tabelle (also hier Person und Anschrift) hat eine 1:1 Beziehung zu einer "Vorgangstabelle"

Diese zwei Zitate wiedersprechen sich irgendwie ?!
Warum? 1 Person, n Detailtabelle und jede Detailtabelle hat 1 Vorgangsdatensatz.

Ich bin Dir dankbar für Deine Mühe, habe aber das Gefühl, dass Du Dich zu sehr auf einzelne Details fixierst und dabei nicht richtig versuchst, meine Beschreibung des fachlichen Zusammenhangs zu verstehen. Vielleicht würde es dann klarer. Nicht falsch verstehen! Ich bin dankbar für jeden, der sich die Mühe macht hier zu helfen. Ich habe nur das Gefühl wir drehen uns im Kreis...
Zitat von Khalid
Schau dir mal das EAV Datenbankmodell an. Damit kann man sowas von der Datenbank Seite her recht einfach abbilden, von der Reporting Seite her wird es allerdings komplizierter.

Bist du auf den SQL Server angewiesen, oder kannst du ggf. umstellen? Wenn ja, ist dies ein typischer Fall für NoSQL (z.B. MobgoDB).
Interessante Idee. Leider ist die Anwendung bereits zu groß und komplex um noch an den Fundamenten zu rütteln. Aber ich glaube EAV würde auch nicht in die richtige Richtung gehen, wenn ich es richtig verstehe. Es ist nicht nur ein Attribute-Value-Pair, das jeweils in einer Detailtabelle steht... Ich verfluche gerade meine angebrachten Beispiele ;-)

Wie gesagt: In den meisten Fällen (mind. 80 der 90 Detailtabellen) geht es um die historische Speicherung von Anwendungsfällen zu einer Person. Von wann bis wann war sie krank. Hat sie Atteste zur Krankheit vorgelegt? Wann hat sie die Krankheit gemeldet?...
Soll nur ein Beispiel dafür sein, dass in den Detailtabellen richtig "Leben" steckt.

Ist die Konstellation wirklich so ungewöhnlich, dass ihr mich davon abbringen wollt? Ich hatte sie immer für vollkommen alltäglich gehalten. Wahrscheinlich war mein Beispiel einfach irreführend.

Wenn man sich nochmal die Problembeschreibung (mein 3. Beitrag hier) ansieht: Ist die Einführung einer 1:1 verknüpften Vorgangstabelle wirklich keine gute Idee?
private Nachricht | Beiträge des Benutzers
Lothi
myCSharp.de - Member

Avatar #avatar-2631.jpg


Dabei seit:
Beiträge: 350
Herkunft: Schweiz

beantworten | zitieren | melden

Eigentlich sehe ich das so wie Diräkt.
Um bei deinem Beispiel zu beiben:
Zitat
historische Speicherung von Anwendungsfällen zu einer Person. Von wann bis wann war sie krank. Hat sie Atteste zur Krankheit vorgelegt? Wann hat sie die Krankheit gemeldet?...
Da ja eine Person mehrer solcher Atteste in seiner Laufbahn bringen kann, ist es keine 1:1 Beziehung mehr.
Auch dein Beispiel mit der Adresse ist keine 1:1 Beziehung. Eine Person kann in seinem Leben mehrmals die Adresse ändern also auch wieder eine 1:n Beziehung.
1:1 verstehe ich zum Beispiel wenn du der Name der Person in einer Tabelle hast und das Geburtsdatum in einer anderen Tabelle.

Alles wickelt sich ja über die Person ID ab.
Du kannst ja schon eine View in der Datenbank mit den Daten, welche in der Vorgangsbaum angezeigt werden sollen, zusammenstellen.
Später kommst du dann ja über die ID auf die einzelnen Daten aus den Tabellen.


Gruss Lothi
private Nachricht | Beiträge des Benutzers
Paschulke
myCSharp.de - Member



Dabei seit:
Beiträge: 63

Themenstarter:

beantworten | zitieren | melden

Der Thread ist langsam zu unübersichtlich. Spricht etwas dagegen, dass ich noch einmal von vorne anfange? Oder wird das hier nicht gerne gesehen?

Das Problem scheint zu sein, dass mein Problem falsch verstanden wird. Nicht die Detailtabellen haben eine 1:1 Beziehung zur Person sondern die Vorgangstabelle zu den Detailtabellen (und auch zur Personentabellen aber das ist ein Sonderfall, den ich erst einmal ausklammern würde)...

Ich würde versuchen aus meinen Beschreibungsfehlern zu lernen und in einem neuen Thread einen neuen Versuch starten. Wäre das ok?
private Nachricht | Beiträge des Benutzers
Lothi
myCSharp.de - Member

Avatar #avatar-2631.jpg


Dabei seit:
Beiträge: 350
Herkunft: Schweiz

beantworten | zitieren | melden

Hmmm... vielleicht verstehst du mich nicht.
Das ist deine Übersicht. Du willst jetzt eine Tabelle die diese Daten enthält um diese dann anzeigen zu können. Über diese Anzeige willst du dann zu den jeweiligen Details gelangen um diese bearbeiten zu können. Richtig?
Zitat
Das sieht in etwas wie folgt aus:
Muster Hans (ID 25)
- Adressen
-- Postanschrift
-- Hauptanschrift
- Kommunikationsdaten
-- E-Mail
-- Telefon
- Dienstverhältnisse
-- 01.01.2008 - 31.12.2009
-- 01.01.2010 - offen
- Fortbildungen
-- 01.01.2008 - 14.01.2008
-- ...

Fett sind Tabellen richtig?
Da kannst doch schön eine Abfrage mit den Daten für die Ansicht in der DB erstellen. Diese nimmst du dann mit ins EF wie eine Tabelle.

Vielleicht seh ich das zu einfach.

Gruss Lothi
private Nachricht | Beiträge des Benutzers
Paschulke
myCSharp.de - Member



Dabei seit:
Beiträge: 63

Themenstarter:

beantworten | zitieren | melden

Wenn ich Dich jetzt richtig verstehe möchtest du eine View erstellen in der ich alle 90 Detailtabellen einbeziehe.
Technisch würde das sicherlich funktionieren. Aber ist das performant? Ich hatte das bisher für so abwegig gehalten, dass ich nicht wirklich darüber nachgedacht hatte.

Aber vielleicht sollte ich das doch einmal tun... ;-)
private Nachricht | Beiträge des Benutzers
Khalid
myCSharp.de - Experte

Avatar #avatar-2534.gif


Dabei seit:
Beiträge: 3627
Herkunft: Hannover

beantworten | zitieren | melden

Ich versuch das mal zu verstehen :)

Greifen wir mal wieder das Beispiel auf
Zitat
Muster Hans (ID 25)
- Adressen
-- Postanschrift
-- Hauptanschrift
- Kommunikationsdaten
-- E-Mail
-- Telefon
- Dienstverhältnisse
-- 01.01.2008 - 31.12.2009
-- 01.01.2010 - offen
- Fortbildungen
-- 01.01.2008 - 14.01.2008
-- ...
Adressen ist eine Tabelle? Postanschrift und Hauptanschrift sind zwei Rows aus der Tabelle Adressen? Wo ist der Vorgang? Ich verstehe diese 1:1 Beziehung einfach nicht. Was steht da drin? Handelt es sich um eine Historisierung/Versionierung? Wenn ja, dann kann es nicht 1:1 sein. Stehen da nur Dinge drin wie Datum erzeugt, Wer erzeugt usw.? Wenn ja, macht 1:1 hier kein Sinn (macht übrigens 1:1 fast nie).

Von den 90 Detailtabellen sind z.B. nur 6 gefüllt? Für den Baum willst du jetzt wissen, welche der 6 Detailtabellen gefüllt sind? Hierzu gibt es jetzt mehrere Möglichkeiten.
Nutzt du Guids? Bei Guid kannst du einfach eine einzige Tabelle reinlegen mit bereits allen IDs aus allen Vorgängen. Zusätzlich kommt in die Tabelle eine Spalte rein, die sagt um welche Tabelle es sich handelt. Jetzt weißt du sofort welche Datensätze in welchen Tabellen für eine Person vorhanden sind. Geht allerdings nicht mehr so einfach mit Ints als PK.

Ansonsten bleibt dir einfach nichts anderes übrig, ausser 90 Abfragen um die Daten zu ziehen. Wenn du das EF jetzt aber z.B. eine Entity mit 90 List<T> Objekten füttert, gehe ich jetzt mal von aus das das EF förmlich explodieren wird. Von Performance kann man dann nicht mehr reden.

Gruß
Khalid

In der Hoffnung, dass ich das Problem korrekt verstanden habe :)
"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)
private Nachricht | Beiträge des Benutzers
Paschulke
myCSharp.de - Member



Dabei seit:
Beiträge: 63

Themenstarter:

beantworten | zitieren | melden

Alles was Du siehst steht in der Vorgangstabelle. Sie ist eine Tabelle, die redundante Daten der Detailtabellen enthält. Sinn der Vorgangstabelle ist wie gesagt ein performanter Aufbau des Vorgangsbaums.
Erst beim Doppelklick auf einen Eintrag (z. B. 01.01.2008 - 14.01.2008) werden die Daten aus der Detailtabelle gelesen (also hier aus der Tabelle Fortbildung).

Ich schließe das Thema jetzt ab. Obwohl alles sehr konfus war, habe ich doch ein paar gute Ideen erhalten. Ich fürchte, dass ich Diräkt doch einmal gekränkt habe. Das war nicht meine Absicht. Sorry! Der Fehler lag wohl offensichtlich eindeutig an mir bzw. meiner schlechten Erklärung.

Vielen Dank für Eure Hilfe!
private Nachricht | Beiträge des Benutzers
witte
myCSharp.de - Member



Dabei seit:
Beiträge: 966

beantworten | zitieren | melden

Hallo,

Du kannst Deine Vorgangstabelle auch als Indexed View lösen, dann brauchst Du sie nicht immer aktualisieren.
private Nachricht | Beiträge des Benutzers
Diräkt
myCSharp.de - Member



Dabei seit:
Beiträge: 619
Herkunft: Schweiz

beantworten | zitieren | melden

Hallo Paschulke
Zitat
Ich schließe das Thema jetzt ab. Obwohl alles sehr konfus war, habe ich doch ein paar gute Ideen erhalten. Ich fürchte, dass ich Diräkt doch einmal gekränkt habe. Das war nicht meine Absicht. Sorry! Der Fehler lag wohl offensichtlich eindeutig an mir bzw. meiner schlechten Erklärung.

Du hast mich absolut nicht gekränkt :-). Da ich das Problem immer noch nicht richtig verstanden habe, und (vielleicht deswegen) mein Lösungsansatz für richtig halte, habe ich mich zurückgehalten und für Dich gehofft, das jemand eine "Lösung" postet die du hören willst :-)

Beste Grüsse

Diräkt
private Nachricht | Beiträge des Benutzers