JDBCTemplate set verschachtelte POJO mit BeanPropertyRowMapper
Gegeben das folgende Beispiel POJO ' s: (unter der Annahme von Get-und Set-Methoden für alle Eigenschaften)
class User {
String user_name;
String display_name;
}
class Message {
String title;
String question;
User user;
}
Kann man leicht Abfragen einer Datenbank (postgres in meinem Fall), und füllen Sie eine Liste der Message-Klassen mit einem BeanPropertyRowMapper, wo das db-Feld übereinstimmen, wird die Eigenschaft in der POJO: (Angenommen, die DB-Tabellen die entsprechenden Felder auf die POJO-Eigenschaften).
NamedParameterDatbase.query("SELECT * FROM message", new BeanPropertyRowMapper(Message.class));
Frage ich mich - ist es eine praktische Möglichkeit zum erstellen einer einzelnen Abfrage und /oder erstellen Sie eine Zeile mapper in solch einer Weise, füllen Sie auch die Eigenschaften der inneren 'user' POJO in der Nachricht.
Ist, Einige syntatical Magie, in dem jedes Ergebnis eine Zeile in der Abfrage:
SELECT * FROM message, user WHERE user_id = message_id
Produzieren eine Liste der Message mit dem zugehörigen Benutzer besiedelten
Anwendungsfall:
Letztlich, die Klassen sind wieder vergangen als serialisierte Objekt aus einer Feder-Controller, die Klassen verschachtelt sind, so dass die resultierende JSON /XML hat eine anständige Struktur.
Im moment, ist diese situation behoben ist, indem Sie zwei Abfragen ausführen und die manuelle Einstellung der Benutzer-Eigenschaft jeder Nachricht in einer Schleife. Brauchbar, aber ich Stelle mir eine elegantere Art und Weise möglich sein sollte.
Update : Lösung -
Großes Lob an @Keeling für die inspiration für die Antwort mit der Nutzung der benutzerdefinierten Zeile mapper - Meine Lösung fügt die Zugabe von bean-Eigenschaft ordnet, um die Automatisierung der Feldzuordnungen.
Nachteil ist die Strukturierung der Abfrage, so dass die entsprechenden Tabellennamen-Präfix (allerdings gibt es keine standard-Konvention zu tun, so daß die Abfrage aufgebaut ist programmatisch):
SELECT title AS "message.title", question AS "message.question", user_name AS "user.user_name", display_name AS "user.display_name" FROM message, user WHERE user_id = message_id
Die benutzerdefinierte Zeile mapper erstellt dann mehrere Bohnen-maps und setzt Ihre Eigenschaften in Bezug auf das Präfix der Spalte: (die Verwendung von meta-Daten, um die Spalte name).
public Object mapRow(ResultSet rs, int i) throws SQLException {
HashMap<String, BeanMap> beans_by_name = new HashMap();
beans_by_name.put("message", BeanMap.create(new Message()));
beans_by_name.put("user", BeanMap.create(new User()));
ResultSetMetaData resultSetMetaData = rs.getMetaData();
for (int colnum = 1; colnum <= resultSetMetaData.getColumnCount(); colnum++) {
String table = resultSetMetaData.getColumnName(colnum).split("\\.")[0];
String field = resultSetMetaData.getColumnName(colnum).split("\\.")[1];
BeanMap beanMap = beans_by_name.get(table);
if (rs.getObject(colnum) != null) {
beanMap.put(field, rs.getObject(colnum));
}
}
Message m = (Task)beans_by_name.get("message").getBean();
m.setUser((User)beans_by_name.get("user").getBean());
return m;
}
Wieder, dies mag wie overkill für ein zwei-Klasse einzusteigen, aber die IRL use case beinhaltet mehrere Tabellen mit zig Feldern.
aktualisiert - TY - hoffe, Sie finden es nützlich
InformationsquelleAutor nclord | 2013-05-23
Du musst angemeldet sein, um einen Kommentar abzugeben.
Vielleicht könnten Sie eine benutzerdefinierte
RowMapper
konnten, dass die Karte, die jede Zeile von einem Aggregat join-Abfrage (zwischen Nachricht und Benutzer), um eineMessage
und verschachtelteUser
. So etwas wie dieses:Von Ihnen positiv bewertet werden - der andere könnte dies ein nützliches Beispiel für eine Zeile mapper für eine einfache verschachtelte POJO.
Bitte sehen Sie sich updates in der ursprünglichen Frage
Ich denke, Sie sollten sich nicht auf die Reihenfolge der zurückgegebenen Felder aus SELECT *.
vereinbart - das ist der Grund, warum ich verwendet, die ResultSetMetaData
InformationsquelleAutor Will Keeling
Frühjahr wurde eine neue
AutoGrowNestedPaths
Eigenschaft in derBeanMapper
- Schnittstelle.Solange die SQL-Abfrage formatiert die Spalte-Namen mit ein . Trennzeichen (wie vor), dann wird die Zeile mapper wird automatisch target inneren Objekte.
Mit diesem, ich habe eine neue generische Zeile mapper wie folgt:
ABFRAGE:
ZEILE MAPPER:
InformationsquelleAutor nclord
Ein bisschen spät, um die Partei aber ich fand wenn ich war googeln die gleiche Frage, und ich fand eine andere Lösung kann günstig sein, für andere in der Zukunft.
Leider gibt es keine native Möglichkeit zur Erreichung der verschachteltes Szenario, ohne dass ein Kunde RowMapper. Jedoch Teile ich, einen einfacheren Weg zu machen, sagte Sie benutzerdefinierte RowMapper als einige andere Lösungen hier.
Ihrem Szenario können Sie Folgendes tun:
Die wichtige Sache zu erinnern, mit
BeanPropertyRowMapper
ist, dass Sie zu Folgen haben, die Benennung der Spalten und die Eigenschaften Ihrer Schüler auf den Brief, mit den folgenden Ausnahmen (siehe Spring-Dokumentation):BeanPropertyRowMapper's
im private final-Felder für eine bessere Leistung auf reusage der wichtigstenmapRow
Methode.InformationsquelleAutor ioneyed
Update: 10/4/2015. Ich normalerweise nicht tun diese rowmapping mehr. Sie erreichen die selektive JSON-Darstellung viel mehr aus über Anmerkungen. Sehen Sie diese gist.
Ich verbrachte den besseren Teil von einem ganzen Tag versuchen, um dies herauszufinden, für meinen Fall der 3-Schicht-verschachtelte Objekte und schließlich nur genagelt. Hier ist meine situation:
Konten (d.h. Benutzer) --1tomany--> Rollen --1tomany--> Ansichten (Benutzer sehen darf)
(Diese POJO-Klassen eingefügt ganz unten.)
Und ich wollte den controller zurückgeben, ein Objekt wie dieses:
Ein wesentlicher Punkt ist, zu erkennen, dass der Frühling nicht nur alle tun dies automatisch für Sie. Wenn Sie Fragen Sie einfach, bis Sie wieder einen Account posten ohne die Arbeit von verschachtelten Objekten, Sie werden nur immer:
So, erste, erstellen Sie Ihre 3-Tabelle SQL-JOIN-Abfrage, und stellen Sie sicher, dass Sie immer alle Daten, die Sie benötigen. Hier ist meins, wie es scheint, auf mein Controller:
Beachten Sie, dass ich bin bei 3 Tabellen. Erstellen Sie nun eine RowSetExtractor Klasse zu setzen, die geschachtelte Objekte zusammen. Die oben genannten Beispiele zeigen, 2-Schicht-Schachteln... damit geht man einen Schritt weiter und hat 3 Ebenen. Beachten Sie, dass ich für die Pflege der second-layer-Objekt in einer Karte als gut.
Und dieser gibt die gewünschte Ausgabe. POJOs unten für Referenz. Hinweis: der @ElementCollection Einstellen der Ansichten, die in der Rolle Klasse. Dies ist, was erzeugt automatisch die role_views Tabelle verwiesen, in der SQL-Abfrage. Wissend, dass die Tabelle vorhanden ist, seinen Namen und seinen Feldnamen ist entscheidend, immer die SQL-Abfrage Recht. Es fühlt sich falsch an, zu haben, zu wissen, dass... es scheint, wie dieses sollte mehr automagic -- ist das nicht, was Frühling ist?... aber ich konnte nicht herausfinden, einen besseren Weg. Sie zu tun haben, die Arbeit manuell in diesem Fall, so weit ich erzählen kann.
InformationsquelleAutor fivedogit
Arbeitete ich sehr auf sowas und sehe nicht ein eleganter Weg, dies zu erreichen, ohne eine or-mapper.
Einfache Lösung basierend auf der Reflexion würde in hohem Maße auf das 1:1 (oder vielleicht auch N:1) Beziehung. Weitere Spalten zurückgegeben werden, die nicht qualifizierte, die von Ihrer Art, so dass man nicht sagen kann, welche Spalten entspricht die Klasse.
Können Sie Weg mit spring-data und QueryDSL. Ich habe nicht Graben hinein, aber ich glaube, Sie brauchen einige meta-Daten für die Abfrage, die später verwendet, um die Karte wieder die Spalten aus der Datenbank in eine richtige Datenstruktur.
Können Sie auch versuchen, die neue postgresql mit json - unterstützen, sieht vielversprechend aus.
HTH
Ich nicht gelten, es aber dennoch ... gerade mit dem Kerl, der dazu beigetragen spring-jpa (ex. hades, wenn du google). machte Sinn für mich.
TY für die Führung - ich kann diese Forschung in die Zukunft
InformationsquelleAutor Steve Oh