【问题标题】:In Jooq, how to fetch into LinkedHashMap?在 Jooq 中,如何获取 LinkedHashMap?
【发布时间】:2021-12-29 17:26:12
【问题描述】:

我知道要插入Map,我可以使用fetchMap,但它不支持LinkedHashMap,我想保持orderBy创建的插入顺序。

我试过了

.
.
.
.orderBy(...)
.collect(
    Collectors.toMap(
        record -> record.field1(), 
        record -> record.field2(), 
        LinkedHashMap.class));

field1field2 部分给了我以下错误。

无法解析“T”中的方法“field1”

希望有人能帮帮我~

谢谢!

解决方案:

根据@Lukas的回答,我试了几次,发现以下几点是必须要做的:

  1. select 方法中,所有字段都必须有类型,除了计算字段,添加类型会引发field not found in field list 错误。

  2. 要为字段添加类型,您必须使用DSL.field(fieldname, type) 方法而不是DSL.field(fieldname).cast(type)。后者会抛出field not found in field list 错误。

  3. collect方法的collector对象中,在获取记录的每个字段时,它们也必须有一个类型。喜欢

record -> record.get(DSL.field("fieldname", Float.class)),

完整的查询将类似于:

Table<Record2<Long, Integer>> table1 = ...;
Table<Record2<Long, Integer>> table2 = ...;
.
.
.
return DSL.
        .select(table1.field("table1_field1", Long.class),
                DSL.ifnull(
                        table1.field("table1_field2", Float.class)
                                .div(table2.field("table2_field1", Float.class)),
                        0)
                        .as("result_table_field1"))
        .from(table1)
        .join(table2)
            .on(table1.field("table1_field1", Long.class)
                    .eq(table2.field("table2_field2", Long.class)))
        .orderBy(DSL.field("result_table_field1"))
        .collect(Collectors.toMap(
                record -> record.get(table1.field("table1_field1", Long.class)),
                record -> record.get(DSL.field("result_table_field1", Float.class)),
                (v1, v2) -> { throw new InvalidResultException("Duplicate key: " + v1); },
                LinkedHashMap::new
        ));

【问题讨论】:

  • 你为什么要声明 LinkedHashMap在你身边?

标签: java mysql jooq


【解决方案1】:

这两种方法都假设您使用的是jOOQ code generator

fetchMap() 已经返回 LinkedHashMap

查看fetchMap() Javadoc。它说:

生成的映射是保留迭代顺序的。

它实际上是一个LinkedHashMap,虽然它不能保证这个确切的类型,所以你必须自担风险。

使用collect()

如果您编写的查询产生Record2 类型,那么您可以使用这样的类型安全收集器:

LinkedHashMap<T1, T2> map =
ctx.select(T.COL1, T.COL2)
   .from(T)
   .orderBy(...)
   .collect(Collectors.toMap(
       Record2::value1,
       Record2::value2,
       (v1, v2) -> { throw new InvalidResultException("Duplicate key: " + v1); },
       LinkedHashMap::new
   ));

您的尝试未编译的原因是:

  1. 您缺少toMap() 的强制mergeFunction 参数
  2. 您应该使用value1()value2(),而不是field1()field2(),但这只有在您的结果集中有类型安全的Record2 时才有效
  3. 如果你没有Record2,而是Record,那么你可以在没有类型安全的情况下工作:
LinkedHashMap<T1, T2> map =
ctx.select(...)
   .from(T)
   .orderBy(...)
   .collect(Collectors.toMap(
       r -> r.get(T.COL1),
       r -> r.get(T.COL2),
       (v1, v2) -> { throw new InvalidResultException("Duplicate key: " + v1); },
       LinkedHashMap::new
   ));

【讨论】:

  • 我明白了。但是如果方法返回LinkedHashMap,就会抛出错误,因为需要的类型是LinkedHashMap,而fetchMap提供的类型是Map。我是否应该简单地转换返回结果,例如return (LinkedHashMap&lt;Long, Float&gt;) DSL.select(...)...fetchMap(...)
  • @powerseed:好吧,你总是可以沮丧,但这可能会在(遥远的)未来打破,那时 jOOQ 的内部可能会决定有比LinkedHashMap 更好的顺序保留地图实现,或者结果应该被包装在一个不可修改的映射等中。具体的实现类型没有声明是有原因的。请参阅我的更新答案以获取替代方案。
  • 嗨 Lukas~ 我尝试了这两种方法,但都给了我错误。前者在Record2::value1Record2::value2 部分抛出Non-static method cannot be referenced from a static context。我的select 就像.select(table1.field("name1"), DSL.ifnull(table1.field("name2").div(table2.field("name3")), 0).as("name4"))
  • 第二次给了我同样的错误类型错误:所需的类型是LinkedHashMap,但提供的只是Map。我将发布问题中错误的屏幕截图。
  • @powerseed:嗯,您在原始问题中省略了您的查询,这就是为什么我假设您像大多数 jOOQ 用户一样使用代码生成器。你为什么不使用代码生成器?否则你不会得到任何类型安全。
猜你喜欢
  • 2010-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-24
  • 1970-01-01
  • 2022-11-26
  • 2016-04-13
相关资源
最近更新 更多