当前位置: 首页 > 知识库问答 >
问题:

使用jOOQ转换PostgreSQLUUID数组的类型

白哲茂
2023-03-14

我试图将PostgreSQL(9.4)UUID绑定到每个UUID周围的包装类数组。请注意,这些包装器在整个应用程序中都是集成的,因此删除它们不是一个选项。我正在使用jOOQ和它的maven插件(3.5.1)来生成PoJo、记录和表类。

我在绑定数据库模式时遇到问题的相关部分如下所示:

create table foo (
    id uuid primary key,
    ids uuid[] not null
);

然后,我尝试使用forcedType元素转换该类,但它生成的类无法编译。放弃这一点,我只是将它们作为UUID生成,直到我遇到一些问题,其中数组值不能转换为UUID,PostgreSQL认为该数组在我的查询中是一个文本数组[1]。

为了解决这个问题,我尝试添加一个绑定和一个转换器,其中转换器用我们的包装器包装UUID,绑定将强制转换表达式添加到生成的SQL中。如果我编写了一个流畅的查询[4],那么这可以很好地工作,但是在插入记录时,它不能正常工作。当我逐段构建数组查询时,insert语句以“array”结束。长度-1’参数化零件。我怀疑我需要重写绑定类的get和set方法,但是我发现这方面的文档有点少。

所以我的问题是,在jOOQ中绑定UUID数组的正确方法是什么,使用还是不使用绑定类?此外,在此过程中是否可以将其转换为T数组?

  1. 查询(名称已更改)
public BazId getBazIdBySearchingFooIdsInReverse(
        @NotNull final OtherId otherId,
        @NotNull final SomethingId somethingId,
        @NotNull final String barTypeName,
        @NotNull final SomethingElseId somethingElseId) {
    final Bar bar = BAR.as("bar");
    final Foo foo = FOO.as("foo");
    return db.select(BAZ.ID)
             .from(BAZ)
             .join(bar)
             .on(BAZ.SOMETHING_ID.eq(bar.SOMETHING_ID))
             .join(foo)
             .on(bar.FOO_ID.eq(foo.ID))
             .join("lateral unnest(foo.ids) with ordinality as x (id,ord)")
             .on("x.id=foo.id")
             .join(BAR_TYPE)
             .on(bar.BAR_TYPE_ID.eq(BAR_TYPE.ID)
                                .and(BAR_TYPE.NAME.equalIgnoreCase(barTypeName)))
             .where(BAZ.SOMETHING_ID.eq(somethingId))
             .and(BAZ.SOMETHING_ELSE_ID.eq(somethingElseId))
             .and(bar.OTHER_ID.eq(otherId))
             .orderBy(DSL.field("x.ord").desc())
             .limit(1)
             .fetchOneInto(BazId.class); //Wraps a UUID
}
public class FooIdsBinding extends DefaultBinding<Object[], FooId[]> {
    private static final long serialVersionUID = 0L;

    private static final UUIDConverter converter = new UUIDConverter();

    public FooIdsBinding() {
        super(new FooIdsConverter());
    }

    @Override
    public void sql(final BindingSQLContext<FooId[]> ctx) {
        final RenderContext render = ctx.render();
        render.sql("array[");
        final UUID[] uuids = ctx.convert(converter).value();
        for (int i = 0, last = uuids.length - 1; i <= last; ++i) {
            render.visit(DSL.val(uuids[i])).sql("::uuid");
            if (i != last) {
                render.sql(',');
            }
        }
        render.sql("]::uuid[]");
    }

    @Override
    public void register(final BindingRegisterContext<FooId[]> ctx) throws SQLException {
        ctx.statement().registerOutParameter(ctx.index(), Types.ARRAY);
    }

    static class BaseUUIDConverter {

        public FooId[] from(final Object[] from) {
            return from == null ? null : Arrays.stream(from)
                                               .map(that -> new FooId((UUID)that))
                                               .collect(Collectors.toList())
                                               .toArray(new FooId[from.length]);
        }

        public UUID[] to(final FooId[] from) {
            return from == null ? null : Arrays.stream(from)
                                               .map(FooId::getUuid)
                                               .collect(Collectors.toList())
                                               .toArray(new UUID[from.length]);
        }

        public Class<FooId[]> toType() {
            return FooId[].class;
        }
    }

    private static class UUIDConverter extends BaseUUIDConverter implements Converter<UUID[], FooId[]> {

        @Override
        public FooId[] from(final UUID[] that) {
            return super.from(that);
        }

        @Override
        public Class<UUID[]> fromType() {
            return UUID[].class;
        }
    }
}
public class FooIdConverter extends FooIdsBinding.BaseUUIDConverter implements Converter<Object[],FooId[]> {
    private static final long serialVersionUID = 0L;

    @Override
    public Class<Object[]> fromType() {
        return (Class)UUID[].class;
    }
}
    db.insertInto(FOO)
      .set(FOO.ID, new FooId())
      .set(FOO.IDS, new FooId[]{new FooId(),new FooId()})
      .execute();
    foo = new FooRecord();
    foo.setId(new FooId());
    foo.setIds(new FooId[]{new FooId(),new FooId()});
    db.executeInsert(foo);

使现代化

我最终得到了这个绑定和转换器,它工作正常。我原以为我需要将数组的每个元素强制转换为uuid,我的实现给jOOQ的sql生成带来了问题,但我认为我只看到了与错误相关的错误,当jOOQ在我将绑定#寄存器#重写为数组之前。

>

  • 转换器

    public class FooIdConverter implements Converter<Object[],FooId[]> {
    
        private static final long serialVersionUID = 1L;
    
        @Override
        public FooId[] from(final Object[] from) {
            return from == null ? null : Arrays.stream(from)
                                               .map(that -> new FooId((UUID)that))
                                               .collect(Collectors.toList())
                                               .toArray(new FooId[from.length]);
        }
    
        @Override
        public UUID[] to(final FooId[] from) {
            return from == null ? null : Arrays.stream(from)
                                               .map(FooId::getUuid)
                                               .collect(Collectors.toList())
                                               .toArray(new UUID[from.length]);
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public Class<Object[]> fromType() {
            return (Class)UUID[].class;
        }
    
        @Override
        public Class<FooId[]> toType() {
            return FooId[].class;
        }
    }
    

    结合

    public class FooIdBinding extends DefaultBinding<Object[], FooId[]> {
    
        private static final long serialVersionUID = 1L;
    
        public FooIdBinding() {
            super(new FooIdConverter());
        }
    
        @Override
        public void sql(final BindingSQLContext<FooId[]> ctx) {
            super.sql(ctx);
            ctx.render().sql("::uuid[]");
        }
    
        @Override
        public void register(final BindingRegisterContext<FooId[]> ctx) throws SQLException {
            ctx.statement().registerOutParameter(ctx.index(), Types.ARRAY);
        }
    
        @Override
        public void get(final BindingGetResultSetContext<FooId[]> ctx) throws SQLException {
            ctx.value(_convert(ctx.resultSet().getArray(ctx.index())));
        }
    
        @Override
        public void get(final BindingGetStatementContext<FooId[]> ctx) throws SQLException {
            ctx.value(_convert(ctx.statement().getArray(ctx.index())));
        }
    
        @Override
        public void get(final BindingGetSQLInputContext<FooId[]> ctx) throws SQLException {
            ctx.value(_convert(ctx.input().readArray()));
        }
    
        @Override
        public void set(final BindingSetStatementContext<FooId[]> ctx) throws SQLException {
            final PreparedStatement ps = ctx.statement();
            ps.setArray(ctx.index(), ps.getConnection().createArrayOf("uuid", ctx.value()));
        }
    
        @Override
        public void set(final BindingSetSQLOutputContext<FooId[]> ctx) throws SQLException {
            throw new UnsupportedOperationException();
        }
    
        protected FooId[] _convert(final Array array) throws SQLException {
            if (array == null) {
                return null;
            } else {
                return converter().from(((UUID[]) array.getArray()));
            }
        }
    }
    
  • 共有1个答案

    荀学文
    2023-03-14

    jOOQ代码生成器中似乎存在一个bug,它阻止覆盖UUID[]类型:#4388

     类似资料:
    • 在我的jOOQ配置文件中,我为日期字段定义了一个转换器,但是在forcedType的节中定义类型的条件时遇到了一些问题。 对于测试,我使用了表达式: 以及在类型上: 我希望匹配数据类型为DATE的所有列。取而代之的是,它不匹配任何一个列,除了一个类型为DATE的列之外,就像其他不匹配的列一样,但这个列的def:CURRENT DATE列似乎与此匹配。 为了让它工作,我必须使用: 有人能给我解释一下

    • 我正在使用jOOQ向一个多对多关系的表中插入相当多的行。代码可以工作,生成的SQL与预期的一样,我的问题是我希望jOOQ代码可以更简单。 我有一个简化的结构(所有东西都重命名了,大部分字段被删除了,大部分约束被删除了,这只是一个愚蠢但准确的结构示例): 我的插入代码: 是否有任何方法可以实现相同(或等效)的结果查询,而不使用不干净的调用,直接将字段传递到某个地方?

    • 我不想重新开始UUID与串行整数密钥的争论。我知道双方都有正确的观点。我在几个表中使用UUID作为主键。 列类型: 索引: 主键约束: 这是我的第一个问题;使用PostgreSQL 9.4,将列类型设置为UUID是否有任何性能优势? 文档 http://www.postgresql.org/docs/9.4/static/datatype-uuid.html 描述了UUID,但是除了类型安全之外,

    • 在我的Oracle数据库中,我有存储为VARCHAR的数量值。从数据库中检索记录时,我希望将它们映射到一个POJO,其中金额值表示为double。不幸的是,我不能使用强制类型,因为在数据库中,所有内容都存储为VARCHAR,并且没有模式将列标识为包含金额值的列。 我正在查看jOOQ转换器,这似乎是我想要的。因此,我为此创建了一个jOOQ转换器: 然而,每当我想使用将数据库记录映射到我的POJO时,

    • MySQL不接受此处生成的datetime值。我探索并发现jOOQ转换器可以用于自定义转换。我可以找到如何在获取数据时使用转换的示例,但无法弄清楚如何在查询时使用转换器。如何使用jOOQ转换器生成SQL而不生成代码?或者是否有更好的方法为SQL生成此查询。

    • 问题内容: 给定一个NumPy数组,如何将其转换为 原位 ?所以基本上,我想做 而不复制阵列。好大 这样做的原因是我有两种算法来计算。其中一个返回一个数组,另一个返回一个数组(这是两种不同算法所固有的)。所有进一步的计算都假定是的数组。 目前,我在通过调用的C函数中进行了转换。有没有办法在Python中做到这一点? 问题答案: 您可以使用其他dtype创建视图,然后就地复制到视图中: 产量 要显示