Учитывая следующий пример POJO: (Предположим, что Getters и Setters для всех свойств)
class User {
String user_name;
String display_name;
}
class Message {
String title;
String question;
User user;
}
Можно легко запросить базу данных (postgres в моем случае) и заполнить список классов сообщений с помощью BeanPropertyRowMapper, где поле db сопоставило свойство в POJO: (Предположим, что таблицы DB имеют соответствующие поля для свойств POJO).
NamedParameterDatbase.query("SELECT * FROM message", new BeanPropertyRowMapper(Message.class));
Мне интересно - есть ли удобный способ построить один запрос и/или создать сопоставление строк таким образом, чтобы также заполнить свойства внутреннего "пользовательского" POJO в сообщении.
То есть, некоторые синтаксические магии, где каждая строка результата в запросе:
SELECT * FROM message, user WHERE user_id = message_id
Создайте список сообщений с ассоциированным пользователем
Случай использования:
В конечном итоге классы передаются обратно как сериализованный объект из контроллера Spring, классы вложены так, что полученный JSON/XML имеет приличную структуру.
В настоящий момент эта ситуация разрешается путем выполнения двух запросов и вручную настраивает пользовательское свойство каждого сообщения в цикле. Полезно, но я думаю, что более элегантный способ должен быть возможен.
Обновление: Используемое решение -
Престижность @Will Keeling для вдохновения для ответа с использованием настраиваемого сопоставления строк. Мое решение добавляет дополнение карт свойств bean, чтобы автоматизировать назначения полей.
Предостережение структурирует запрос так, чтобы соответствующие имена таблиц были префиксными (однако для этого не существует стандартного соглашения, поэтому запрос создается программно):
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
Затем настраиваемый сопоставитель строк создает несколько карт bean и устанавливает их свойства на основе префикса столбца: (используя метаданные для получения имени столбца).
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;
}
Опять же, это может показаться излишним для объединения двух классов, но пример использования IRL включает несколько таблиц с десятками полей.