Frage

Beispiel

Ich habe Person, SpecialPerson, und User. Person und SpecialPerson sind nur Menschen - Sie haben keine Benutzernamen oder Ihr Passwort auf einer Website, aber Sie sind in einer Datenbank gespeichert, für die Aufzeichnung.Benutzer hat alle die gleichen Daten wie Person und möglicherweise SpecialPerson, zusammen mit einer Benutzer-name und Passwort, wie Sie mit der Website registriert.


Wie würden Sie dieses problem beheben?Würde Sie haben einen Person Tabelle speichert alle Daten gemeinsam zu einer person und verwenden eine Schlüssel zu suchen, die Ihre Daten in SpecialPerson (wenn Sie eine spezielle person) und Benutzer (falls Sie ein Benutzer sind) und vice-versa?

War es hilfreich?

Lösung

Es gibt grundsätzlich drei Möglichkeiten der Zuordnung-Objekt, Vererbung, um Datenbank-Tabellen.

Sie können machen eine große Tabelle mit allen Feldern, von allen Objekten, die mit einem speziellen Feld für den Typ.Dies ist schnell, aber verschwendet Platz, obwohl moderne Datenbanken Speicherplatz sparen, indem Sie nicht die Lagerung der leeren Felder.Und wenn Sie nur suchen für alle Benutzer in der Tabelle, mit jeder Art von person, die in ihm können sich die Dinge langsam.Nicht alle or-Mapper zu unterstützen.

Können Sie andere Tabellen für die verschiedenen Unterklassen, die alle Tabellen enthält die Basis-Klasse Felder.Ist das ok aus performance-Perspektive.Aber nicht für die Wartung Perspektive.Jedes mal, wenn Sie Ihre Basis-Klasse alle änderungen der Tabellen ändern.

Sie können auch eine Tabelle pro Klasse, wie Sie vorgeschlagen.Auf diese Weise müssen Sie die joins aus, um alle Daten.So ist es weniger performant.Ich denke, es ist die sauberste Lösung.

Was Sie verwenden möchten, hängt natürlich von Ihrer situation.Keine der Lösungen ist perfekt, also müssen Sie Wiegen die vor-und Nachteile.

Andere Tipps

Werfen Sie einen Blick auf Martin Fowler ' s Muster der Enterprise Application Architecture:

  • Single Table Inheritance:

    Wenn die Zuordnung zu einer relationalen Datenbank, wir versuchen zu minimieren die joins, die können schnell montieren bei der Bearbeitung einer vererbungsstruktur in mehreren Tabellen.Single Table Inheritance Karten alle Felder aller Klassen einer erbschaft Struktur in einer einzigen Tabelle.

  • Klasse Tabelle Vererbung:

    Sie möchten, die Datenbank-Strukturen, die Karte deutlich auf die Objekte und links zuzulassen, überall in der vererbungsstruktur.Klasse Tabelle Vererbung unterstützt dies durch die Verwendung einer Datenbank-Tabelle pro Klasse in der vererbungsstruktur.

  • Konkrete Tabelle Vererbung:

    Denken Tabellen aus einer Objekt-Instanz Sicht ein sinnvoller Weg ist, um jedes Objekt im Speicher, und ordnen Sie Sie auf einer einzigen Datenbank-Zeile.Dies bedeutet, Konkrete Tabelle Vererbung, wo gibt es eine Tabelle für jede konkrete Klasse in der Vererbungshierarchie.

Wenn der Benutzer, der Person und die Besonderen Menschen haben alle die gleichen Fremdschlüssel, dann hätte ich eine einzelne Tabelle.Fügen Sie eine Spalte mit der Bezeichnung Typ, die ist beschränkt auf den Benutzer, eine Person oder eine Besondere Person.Dann basierend auf dem Wert des Typs haben Einschränkungen auf die andere optionale Spalten.

Für den Objekt-code, es macht nicht viel Unterschied, wenn Sie haben separate Tische oder mehrerer Tabellen darzustellen Polymorphismus.Allerdings, wenn Sie haben zu tun SQL gegen die Datenbank, ist es viel einfacher, wenn der Polymorphismus ist gefangen in Einzel-Tisch...vorausgesetzt, die Fremdschlüssel für die sub-Typen sind die gleichen.

Was ich sagen werde, hier wird zum senden von Datenbank-Architekten in conniptions aber hier geht:

Betrachten Sie eine Datenbank Ansicht als das äquivalent einer interface-definition.Und ein Tisch ist das äquivalent von eine Klasse.

Also in deinem Beispiel, alle 3 person-Klassen implementieren das interface IPerson.So haben Sie 3 Tabellen - eine für jeden von 'User', 'Person' und 'SpecialPerson'.

Dann werfen Sie einen Blick 'PersonView' oder was auch immer, wählt die gemeinsamen Eigenschaften (definiert durch Ihre "Schnittstelle") aus allen 3 Tabellen in der Ansicht.Verwenden Sie ein "PersonType" Spalten in dieser Ansicht zum speichern der tatsächlichen Typ der person, gespeichert.

Also, wenn Sie ausführen eine Abfrage, die kann betrieben werden auf jede Art von person, nur die Abfrage der PersonView anzeigen.

Dies ist möglicherweise nicht das, was der OP gemeint zu Fragen, aber ich dachte, ich könnte werfen Sie das hier.

Vor kurzem hatte ich einen eindeutigen Fall von db-Polymorphismus in einem Projekt.Wir hatten zwischen 60 bis 120 möglichen Klassen, jede mit Ihren eigenen Satz von 30 bis 40 einzigartige Attribute und etwa 10 - 12 gemeinsame Attribute für alle Klassen .Wir haben uns entschieden, die SQL-XML-route und endete mit einer einzelnen Tabelle.Etwas wie :

PERSON (personid,persontype, name,address, phone, XMLOtherProperties)

mit allen gemeinsamen Eigenschaften als Spalten und dann ein großes XML-Eigenschaft bag.Die ORM-Schicht wurde dann verantwortlich für das Lesen/schreiben der jeweiligen Eigenschaften aus der XMLOtherProperties.Etwas wie :

 public string StrangeProperty
{
get { return XMLPropertyBag["StrangeProperty"];}
set { XMLPropertyBag["StrangeProperty"]= value;}
}

(wir landeten mapping der xml-Spalte als eine Hastable eher als ein XML-Dokument, aber Sie können verwenden, was auch immer Anzüge Ihre DAL besten)

Es ist nicht zu gewinnen alle Auszeichnungen für Ihr design, aber es wird funktionieren, wenn Sie haben eine große (oder unbekannte) Anzahl der möglichen Klassen.Und in SQL2005 Sie können immer noch verwenden von XPATH in Ihren SQL-Abfragen wählen Sie Zeilen basierend auf einer Eigenschaft, die als XML gespeichert..es ist nur eine kleine Leistungseinbußen zu nehmen.

Es gibt drei grundlegende Strategien für den Umgang mit der Vererbung in einer relationalen Datenbank und einer Reihe komplexer/bespoke-alternativen, je nach Ihren genauen Anforderungen.

  • Tabelle pro Klassenhierarchie.Eine Tabelle für die gesamte Hierarchie.
  • Tabelle pro Unterklasse.Wird eine separate Tabelle erstellt, die für jeden sub-Klasse mit einem 0-1 Assoziation zwischen den Unterklassen-Tabellen.
  • Tabelle pro konkrete Klasse.Eine einzelne Tabelle erstellt wird, für jede konkrete Klasse.

Jeder, der diese appoaches wirft seine eigenen Probleme über die Normalisierung der Daten auf code und Daten Speicher, obwohl meine persönliche preferance zu verwenden Tabelle pro Unterklasse es sei denn, es gibt eine bestimmte Leistung oder strukturellen Grund zu gehen, mit einem der alternativen.

Auf die Gefahr des seins eine 'Architektur astronaut' hier, ich würde eher geneigt sein, zu gehen mit separaten Tabellen für die Unterklassen.Die Primärschlüssel der Unterklasse Tabellen auch eine foreign key-Link zurück zu der Supertyp.

Der Hauptgrund für diesen Weg ist, dass es wird dann viel mehr logisch konsistent und Sie nicht am Ende mit einer Menge der Felder, die NULL sind und unsinnig für diesen bestimmten Datensatz.Diese Methode macht es auch viel mehr einfach zusätzliche Felder hinzufügen, um die Subtypen wie Sie Durchlaufen Ihren design-Prozess.

Dies gilt fügen Sie den Nachteil das hinzufügen von Verknüpfungen auf Ihre Fragen, die sich auf die Leistung auswirken kann, aber ich gehen fast immer mit einem idealen design erste, und dann schauen Sie zu optimieren, werden später, wenn es sich als notwendig erweist.Die wenigen Male, die ich gegangen der "optimale" Weg zuerst habe ich fast immer bereut es später.

Also mein design wäre so etwas wie

PERSON (personid, name, Adresse, Telefonnummer, ...)

SPECIALPERSON (personid REFERENCES PERSON(personid), zusätzliche Felder,...)

BENUTZER (personid REFERENCES PERSON(personid), username, encryptedpassword, zusätzliche Felder,...)

Sie könnten auch Ansichten erstellen, die später auf dieser Aggregate, die der Supertyp und Subtyp, wenn dies notwendig ist.

Der eine Fehler bei diesem Ansatz ist, wenn du dich stark auf der Suche für die Subtypen zugeordnet particulare Supertyp.Es gibt keine einfache Antwort auf diese aus der Spitze von meinem Kopf, Sie könnte track es programmgesteuert, wenn notwendig, sonst laufen soem Globale Abfragen und speichern die Ergebnisse.Es wirklich hängt von der Anwendung ab.

Ich würde sagen, dass, je nachdem was unterscheidet die Person und die Spezielle Person, die Sie wahrscheinlich nicht wollen, Polymorphismus für diese Aufgabe.

Ich würde erstellen Sie eine Benutzer-Tabelle, eine Person, Tabelle, dass hat eine null-Fremdschlüssel-Feld User (ich.e, die Person kann ein Benutzer, aber nicht muss).
Dann würde ich einen SpecialPerson Tabelle bezieht sich auf die Person-Tabelle mit diversen Feldern.Wenn ein Datensatz vorhanden ist, in SpecialPerson für eine bestimmte Person.ID er/Sie/es ist eine Besondere person.

In unserer Firma beschäftigen wir uns mit Polymorphismus durch die Kombination aller Felder in einer Tabelle, und seine schlimmsten und keine referenzielle Integrität erzwungen werden können, und sehr schwer zu verstehen-Modell.Ich würde empfehlen, gegen diesen Ansatz für Sie sicher.

Ich gehe mit Tabelle pro Unterklasse und vermeiden Sie auch performance-hit, aber mit ORM, wo können wir vermeiden, dass er sich mit allen Unterklasse Tabellen durch den Bau der Abfrage auf die Fliegen, indem auf der Basis von Typ.Die oben genannten Strategie funktioniert für einzelne Datensatz-Ebene ziehen, aber für bulk update, oder wählen Sie Sie können nicht vermeiden es.

ja, ich würde auch überlegen, eine TypeID zusammen mit einer PersonType Tabelle, wenn es ist möglich, es wird mehr Arten.Allerdings, wenn es nur 3, das sollte nicht sein, nec.

Dies ist ein älterer Beitrag, aber ich dachte, ich werde sich Wiegen, von einem konzeptionellen, Verfahrens-und performance-Standpunkt aus.

Die erste Frage, die ich stellen würde, ist die Beziehung zwischen person, specialperson, und Benutzer, und ob es möglich ist, jemand zu sein beide ein specialperson und ein Benutzer gleichzeitig.Oder, irgendein anderer der 4 möglichen Kombinationen (Klasse a + b Klasse b + c, Klasse a + c oder a + b + c).Wenn diese Klasse gespeichert, die einen Wert in einem type Feld und daher würde zusammenbrechen diese Kombinationen, und dass der Zusammenbruch nicht akzeptabel ist, dann würde ich denken, eine sekundäre Tabelle erforderlich wäre, so dass für eine eins-zu-viele-Beziehung.Ich habe gelernt, die Sie nicht beurteilen Sie, bis Sie bewerten die Verwendung und die Kosten der Verlust Ihrer Kombination von Informationen.

Der andere Faktor, das macht mich zu lehnen in Richtung einer einzigen Tabelle ist die Beschreibung des Szenarios. User ist die einzige Entität ist, sich mit einem Benutzernamen (sagen varchar(30)) und das Passwort (sagen varchar(32)).Wenn Sie die Allgemeinen Felder möglich, die Länge ist durchschnittlich 20 Zeichen pro 20 Felder, dann Ihre Spalte, die Erhöhung der Größe 62-über 400 oder 15% - 10 Jahren gewesen wäre teurer, als es mit modernen RDBMS-Systemen, vor allem mit einem Feld Art wie varchar (z.B.für MySQL) zur Verfügung.

Und wenn Sicherheit wichtig ist, um Sie, könnte es vorteilhaft sein, eine sekundäre eins-zu-eins-Tabelle genannt credentials ( user_id, username, password).Tabelle aufgerufen werden, in einer JOIN-kontextuell zu sagen, die Zeit der Anmeldung, aber baulich getrennt ist, nur aus "jedermann" in der Haupttabelle.Und eine LEFT JOIN ist für Abfragen verfügbar, die vielleicht zu prüfen "registrierte Benutzer".

Mein Hauptanliegen seit Jahren ist noch zu prüfen, das Objekt, die Bedeutung (und damit mögliche Entwicklung) außerhalb der DB und in der realen Welt.In diesem Fall, alle Arten von Personen haben, schlagenden Herzen (ich hoffe), und kann auch haben hierarchisches Verhältnis zueinander;also, in meinem Hinterkopf, auch wenn nicht jetzt, müssen wir speichern solche Beziehungen mit einer anderen Methode.Das ist nicht explizit in Bezug auf Ihre Frage hier, aber es ist ein weiteres Beispiel für den Ausdruck, der ein Objekt-Beziehung.Und jetzt (7 Jahre später), sollten Sie einen guten Einblick in, wie Sie Ihre Entscheidung trotzdem funktionierte :)

In der Vergangenheit habe ich es getan, genau wie Sie vorschlagen-haben eine Person, Tabelle für Allgemeine Sachen, dann SpecialPerson verbunden, die für die abgeleitete Klasse.Allerdings, bin ich wieder denken, als Linq2Sql möchte ein Feld in derselben Tabelle zeigen den Unterschied.Ich habe Sie noch nicht angeschaut, das entity-Modell zu viel, obwohl-ziemlich sicher, dass ermöglicht Sie die andere Methode.

Ich persönlich würde store all diese verschiedenen Benutzer-Klassen in einer einzigen Tabelle.Sie können dann entweder ein Feld speichert eine 'Type' Wert, oder Sie bedeuten kann, welche Art von person Sie es zu tun haben mit dem, was Felder ausgefüllt sind.Für Beispiel, wenn Benutzer id ist NULL, dann wird dieser Datensatz ist nicht ein Benutzer.

Sie könnten den link, um in anderen Tabellen mit einer eins-zu-eins-oder-nichts-Art von join, aber dann in jeder Abfrage werden Sie zusätzliche Verknüpfungen.

Die erste Methode ist auch unterstützt durch LINQ-to-SQL, wenn Sie sich entscheiden zu gehen, dass die route (Sie nennen es "Tabelle Pro Hierarchie' oder 'TPH').

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top