【问题标题】:Convert types of PostgreSQL UUID arrays using jOOQ使用 jOOQ 转换 PostgreSQL UUID 数组的类型
【发布时间】:2015-08-25 09:28:51
【问题描述】:

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

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

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

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

为了解决这个问题,我尝试添加Binding [2] 和Converter [3],其中转换器使用我们的包装器包装UUID,并且绑定将强制转换表达式添加到生成的SQL .如果我编写流畅的查询 [4],这可以正常工作,但是在插入 Record [5] 时无法正常工作。当我逐个构建数组查询时,插入语句以“array.length - 1”参数化部分结束。我怀疑我需要覆盖Binding 类的#get#set 方法,但是我发现文档在这方面有点轻。

所以我的问题是,在 jOOQ 中绑定 UUID 数组的正确方法是什么,无论是否使用 Binding 类?此外,是否可以在过程中将其转换为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
}
  1. 绑定
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;
        }
    }
}
  1. 转换器。必须是 Object[] 才能使生成的 Table 编译
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;
    }
}
  1. 有效的查询
    db.insertInto(FOO)
      .set(FOO.ID, new FooId())
      .set(FOO.IDS, new FooId[]{new FooId(),new FooId()})
      .execute();
  1. 一个没有的查询
    foo = new FooRecord();
    foo.setId(new FooId());
    foo.setIds(new FooId[]{new FooId(),new FooId()});
    db.executeInsert(foo);

更新

我最终将它用于绑定和转换器,它工作正常。我曾认为我需要将数组的每个元素转换为 uuid,我的实现导致 jOOQ 的 sql 生成出现问题,但我认为在我将 Binding#register 覆盖为 ARRAY 之前,我只看到与 jOOQ 相关的错误.

  1. 转换器

    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;
        }
    }
    
  2. 绑定

    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()));
            }
        }
    }
    

【问题讨论】:

  • 有趣的更新,这对未来的访问者将非常有用。但请注意,您也可以在 Stack Overflow 上为您自己的问题提供答案...
  • 嘿@LukasEder,谢谢你看这个。我的问题真的是,'什么是正确的方法',而不是'我怎样才能让它工作',因为我知道我可以一起破解一些东西,而且 IMO 你的答案是正确的。即它应该使用常规的自定义/强制类型机制,只需要一个转换器。

标签: java arrays postgresql jooq


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2018-11-30
    • 2014-09-16
    • 1970-01-01
    • 2014-11-24
    • 2014-09-13
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多