5 Stimmen

Bester Weg, um einen Baum von Objekten zu holen, die in einem RDBMS gespeichert sind

Diese Frage soll software- und plattformunabhängig sein. Ich bin nur auf der Suche nach allgemeinem SQL-Code.

Betrachten Sie die folgenden (sehr einfachen, als Beispiel dienenden) Tabellen:

Table: Authors
id   | name
1    | Tyson
2    | Gordon
3    | Tony
etc

Table: Books
id   | author   | title
1    | 1        | Tyson's First Book
2    | 2        | Gordon's Book
3    | 1        | Tyson's Second Book
4    | 3        | Tony's Book
etc

Table: Stores
id   | name
1    | Books Overflow
2    | Books Exchange
etc

Table: Stores\_Books
id   | store   | book
1    | 1       | 1
2    | 2       | 4
3    | 1       | 3
4    | 2       | 2

Wie Sie sehen können, gibt es eine eins-zu-viele-Beziehung zwischen Book s und Author s und eine Many-to-many-Beziehung zwischen Book s und Store s.

Frage eins: Was ist die beste Abfrage, um einen Autor und seine Bücher (und wo die Bücher verkauft werden) in ein objektorientiertes Programm zu laden, in dem jede Zeile eine Objektinstanz darstellt?

Frage zwei: Was ist die beste Abfrage, um den gesamten Objektbaum in ein objektorientiertes Programm zu laden, in dem jede Zeile eine Objektinstanz darstellt?

Beide Situationen sind leicht vorstellbar, wenn es um träges Laden geht. In beiden Fällen würden Sie den Autor mit einer Abfrage abrufen und dann, sobald Sie seine Bücher benötigen (und in welchen Geschäften die Bücher verkauft werden), eine weitere Abfrage verwenden, um diese Informationen zu erhalten.

Ist Lazy Loading der beste Weg, dies zu tun, oder sollte ich eine Verknüpfung verwenden und das Ergebnis beim Erstellen des Objektbaums analysieren (in einem Versuch, die Daten eifrig zu laden)? Was wäre in dieser Situation die optimale Verknüpfung/Zielausgabe aus der Datenbank, um das Parsing so einfach wie möglich zu gestalten?

Soweit ich sagen kann, mit Eager Loading, würde ich brauchen, um ein Wörterbuch oder Index einer Art von allen Objekten zu verwalten, während ich die Daten parsen bin. Ist dies tatsächlich der Fall oder gibt es einen besseren Weg?

3voto

ratsbane Punkte 880

Das ist eine schwer zu beantwortende Frage. Ich habe das schon einmal gemacht, indem ich eine Abfrage geschrieben habe, die alles als flache Tabelle zurückgibt, und dann in einer Schleife durch die Ergebnisse gegangen bin und Objekte oder Strukturen erstellt habe, wenn sich die wichtigsten Spalten geändert haben. Ich denke, das funktioniert besser als mehrere Datenbankaufrufe, da jeder Aufruf eine Menge Overhead verursacht, aber je nachdem, wie viele kleinere Entitäten es zu jeder großen Entität gibt, ist das vielleicht nicht das Beste.

Für Ihre beiden Fragen 1 und 2 könnte Folgendes gelten.

SELECT a.id, a.name, b.id, b.name FROM authors a LEFT JOIN books b ON a.id=b.author

(Pseudocode, in Ihrem Programm, das den db-Aufruf tätigt)

while (%row=fetchrow) {
   if ($row{a.id} != currentauthor.id) {
      currentauthor.id=$row{a.id};
      currentauthor.name=$row{a.name};
      }
    currentbook=new book($row{b.id, b.name});
    push currentauthor.booklist, currentbook;
    }

[Ich habe gerade gemerkt, dass ich den zweiten Teil Ihrer Frage nicht beantwortet habe. Je nach Größe der zu speichernden Daten und je nachdem, was ich damit machen wollte, würde ich entweder

Vor der Schleife durch Bücher/Autoren wie oben, schlürfen die ganze speichert Tabelle in eine Struktur in meinem Programm, ähnlich wie das Buch/Autor-Struktur oben, aber indiziert durch die storeid, und dann ein Lookup in dieser Struktur jedes Mal, wenn ich ein Buch Datensatz lesen und speichern Sie einen Verweis auf die Tabelle speichern

oder, wenn es viele Geschäfte gibt,

Verbinden Sie die Läden mit den Büchern und fügen Sie in dem Teil des Codes, der ein Buch hinzufügt, eine zusätzliche verschachtelte Schleife hinzu, um die Objekte der Läden hinzuzufügen.

Hier ist ein entsprechender Wikipedia-Artikel: http://en.wikipedia.org/wiki/Object-relational_impedance_mismatch

Ich hoffe, das hilft!

2voto

djna Punkte 53789

In einem OO-Programm verwenden Sie kein SQL, sondern lassen dies unsichtbar von Ihrem Persistenzmechanismus erledigen. Zur Erklärung:

Wenn Sie ein objektorientiertes Programm haben, dann wollen Sie ein Objektmodell, das die Konzepte von Autor, Buch und Geschäft auf natürliche Weise darstellt. Sie haben dann ein "Objekt/Relationales Mapping"-Problem. Irgendwie wollen Sie Daten aus der Datenbank mit SQL abrufen und trotzdem natürlich mit Ihren Objekten arbeiten.

In der Java-Welt machen wir das mit der Java Persistence API (JPA). Man schreibt nicht wirklich das SQL, sondern "annotiert" nur die Java-Klasse, um zu sagen: "Diese Klasse entspricht dieser Tabelle, dieses Attribut dieser Spalte", und macht dann einige interessante Dinge mit den JOINs und kann in der Tat entweder Lazy oder Eager Loading wählen, je nachdem, was sinnvoll ist.

Sie könnten also mit einer Autorenklasse enden (ich mache die Attribute hier der Kürze halber öffentlich, im wirklichen Leben haben wir private Attribute und Getter und Setter.

 @Entity
 public Class Author {
     public int id; 
     public String name;
     // more in a minute

Diese Klasse ist als Entität annotiert, so dass JPA die Attribute in den Objekten mit ihren Spalten in der entsprechenden Tabelle abgleichen kann. Die Annotationen haben mehr Möglichkeiten, so dass Sie Zuordnungen zwischen Namen von Attributen und Spalten angeben können, die nicht genau übereinstimmen; Zuordnungen wie

    PUBLISHED_AUTHOR => Author,  
    FULL_NAME => name

Was ist nun mit JOINS und Beziehungen? Die Klasse author hat eine Sammlung von Books

   @Entity
   public Class Author {
     public int id; 
     public String name;
     public List<Book> books;

und die Klasse Book hat ein Attribut, das ihr Autor ist

   @Entity
   public Class Book {
       public int id;
       public String title
       public Author author

Die JPA-Entity-Manager-Klasse holt eine Instanz von Book mithilfe einer Find-Methode (ich werde hier nicht ins Detail gehen)

   int primaryKey = 1;
   Book aBook = em.find( primaryKey); // approximately

Jetzt kann Ihr Code einfach gehen

   aBook.author.name  

Sie sehen nicht, dass SQL verwendet wurde, um die Daten für Book abzurufen, und dass zu dem Zeitpunkt, zu dem Sie nach dem Attribut author fragen, auch die Daten für author abgerufen wurden. Vielleicht wurde ein SQL JOIN verwendet, aber das müssen Sie nicht wissen. Sie können durch weitere Anmerkungen steuern, ob der Abruf "Eager" oder "Lazy" ist.

Ähnlich

    int primaryKey = 2
    Author author = em.find( primaryKey ); 

    author.books.size() ; // how many books did the author write?

wir erhalten eine Liste aller Bücher sowie der Autoren andere Daten, SQL ist passiert, wir haben es nicht gesehen.

1voto

tzup Punkte 3516

Hier ist etwas T-SQL, um Ihnen den Einstieg zu erleichtern:

1.

select a.name, b.title from Authors a join Books b on a.id = b.author

2.

select a.name, b.title, s.name from Autoren a join Bücher b on a.id = b.Autor join Stores_Books sb on sb.book = b.id join Stores s on s.id = sb.store

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X