Java JDBC模板-一对多

Java JDBC模板-一对多,java,spring-jdbc,Java,Spring Jdbc,我有一节课看起来像这样。我需要从下面显示的两个数据库表中填充它。有没有更好的方法 我的想法是让一个服务类通过一个来自DAO的ResultSetExtractor来选择一个列表。然后在该列表上执行一个foreach,并通过另一个ResultSetExtractor为个人选择一个list电子邮件列表,然后使用foreach循环将其附加 有没有更好的方法,或者这是最好的方法 public class Person { private String personId; private S

我有一节课看起来像这样。我需要从下面显示的两个数据库表中填充它。有没有更好的方法

我的想法是让一个服务类通过一个来自DAO的
ResultSetExtractor
来选择一个
列表。然后在该列表上执行一个
foreach
,并通过另一个
ResultSetExtractor
为个人选择一个
list
电子邮件列表,然后使用
foreach
循环将其附加

有没有更好的方法,或者这是最好的方法

public class Person {
    private String personId;
    private String Name;
    private ArrayList<String> emails;
}


 create table Person (
   person_id  varchar2(10),
   name       varchar2(30)
);


create table email (
  person_id   varchar2(10),
  email       varchar2(30)
);
公共类人物{
私人字符串人形;
私有字符串名称;
私人ArrayList电子邮件;
}
创建表格人员(
个人识别号varchar2(10),
姓名varchar2(30)
);
创建表格电子邮件(
个人识别号varchar2(10),
电邮:varchar2(30)
);

这最好通过ORM解决。使用JDBC,您必须手工完成ORM为您所做的事情。执行N+1查询效率非常低。您应该执行单个查询,并手动构建对象。笨重但不难:

select person.id, person.name, email.email from person person
left join email on person.id = email.person_id

...

Map<Long, Person> personsById = new HashMap<>();
while (rs.next()) {
    Long id = rs.getLong("id");
    String name = rs.getString("name");
    String email = rs.getString("email");
    Person person = personsById.get(id);
    if (person == null) {
        person = new Person(id, name);
        personsById.put(person.getId(), person);
    }
    person.addEmail(email);
}
Collection<Person> persons = personsById.values();
选择person.id、person.name、email.email from person
在person.id=email.person\u id上左键加入电子邮件
...
Map personsById=new HashMap();
while(rs.next()){
Long id=rs.getLong(“id”);
字符串名称=rs.getString(“名称”);
String email=rs.getString(“电子邮件”);
Person=personsById.get(id);
if(person==null){
人员=新人员(id、姓名);
personsById.put(person.getId(),person);
}
个人邮件(电子邮件);
}
Collection persons=personsById.values();

我在寻找类似的东西,尽管答案完全正确,但我还是选择了这个漂亮的库

它还与弹簧靴完美集成

主要的优点是,您有一个干净的存储库层,它使用您的pojo并使重构变得更加容易,并且像hibernate一样,您仍然可以将嵌套的深层复杂的一对多映射,并且仍然可以控制执行的内容


它还有一个很好的jdbctemplate CRUD,Java13最终支持多行字符串文字,这对sql语句的可读性非常好。希望这对某人有所帮助:)

在我的情况下,我必须使用
LinkedHashMap
位置
字段对查询结果进行排序

来自JavaDoc

:“此链表定义了迭代顺序,通常是键插入地图的顺序(插入顺序)。请注意,如果键重新插入地图,插入顺序不受影响。”

:“此类不保证映射的顺序,特别是不保证顺序随时间保持不变”

提示:使用
getOrDefault
方法消除了对
nullable
对象的额外检查

public List<BucketDto> findAll() {

    var sql = """
        SELECT
            b.uuid bucket_uuid, b.position bucket_position, b.name bucket_name,
            c.uuid card_uuid, c.position card_position, c.name card_name
        FROM bucket AS b
            LEFT JOIN card AS c ON c.bucket_id = b.id
        ORDER BY b.position ASC, c.position ASC
        """;

    return jdbcTemplate.query(sql, rs -> {

        Map<Double, BucketDto> resultMap = new LinkedHashMap<>();

        while (rs.next()) {

            var position = rs.getDouble("bucket_position");

            var bucketDto = resultMap.getOrDefault(position, new BucketDto(
                UUID.fromString(rs.getString("bucket_uuid")),
                position,
                rs.getString("bucket_name")));

            if (Optional.ofNullable(rs.getString("card_uuid")).isPresent()) {
                bucketDto.addCard(new CardDto(
                    UUID.fromString(rs.getString("card_uuid")),
                    rs.getDouble("card_position"),
                    rs.getString("card_name")));
            }

            resultMap.put(position, bucketDto);
        }

        return new ArrayList<>(resultMap.values());
    });
}
公共列表findAll(){
var sql=“”
挑选
b、 uuid bucket_uuid,b.position bucket_position,b.name bucket_name,
c、 uuid卡,c.职位卡,c.姓名卡
从桶中取出b
在c.bucket_id=b.id上作为c的左连接卡
按b位置ASC、c位置ASC订购
""";
返回jdbcTemplate.query(sql,rs->{
Map resultMap=newlinkedhashmap();
while(rs.next()){
var位置=rs.getDouble(“铲斗位置”);
var bucketDto=结果映射getOrDefault(位置,新bucketDto(
UUID.fromString(rs.getString(“bucket_uid”),
立场,,
rs.getString(“bucket_name”);
if(可选的.ofNullable(rs.getString(“card_uuid”)).isPresent(){
bucketDto.添加卡(新卡DTO(
UUID.fromString(rs.getString(“card_uid”),
rs.getDouble(“卡片位置”),
rs.getString(“卡名”);
}
结果映射放置(位置,Buckedto);
}
返回新的ArrayList(resultMap.values());
});
}

这太棒了。但愿我在以前的项目中做过这件事。你能告诉我最后一行是什么吗?我不确定我是否遵循了这一部分。它只是从映射中获取值,因为您可能希望查询的结果是一组人员,而不是映射。阅读
Map.values()
的javadoc以获取更多详细信息。或者您可以使用
java.util.Set
where
class Person{public boolean equals(Object o){return id==(Person)o.id;public int hashCode(){return id.hashCode();}
避免调用
Map.values()
这对于性能和可读性来说可能更理想。