使用jOOQ

时间:2015-06-10 08:31:56

标签: java arrays postgresql jooq

我正在尝试将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]时无法正常工作,这样可以正常工作。当我逐块构建数组查询时,insert语句以'array.length - 1'参数化部分结束。我怀疑我需要覆盖#get类的#setBinding方法,但我发现这方面的文档有点亮。

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

  1. 查询(名称已更改)
  2. 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. 绑定
    2. 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编译
      2. 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. 有效的查询
        2.     db.insertInto(FOO)
                .set(FOO.ID, new FooId())
                .set(FOO.IDS, new FooId[]{new FooId(),new FooId()})
                .execute();
          
          1. 不符合
          2. 的查询
                foo = new FooRecord();
                foo.setId(new FooId());
                foo.setIds(new FooId[]{new FooId(),new FooId()});
                db.executeInsert(foo);
            

            更新

            我最终得到了绑定和转换器,它工作正常。我以为我需要将数组的每个元素转换为一个uuid,我的实现导致了jOOQ的sql生成问题,但我认为在我超越Binding#register之前我只看到了与jOOQ有关的错误ARRAY。

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

1 个答案:

答案 0 :(得分:1)

看起来jOOQ代码生成器中存在一个错误,导致UUID[]类型被覆盖:#4388