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

如何从SelectConditionStep

曹浩
2023-03-14

我在继续我最后一个关于jOOQ的问题。在Hibernate模型中,使用了过滤器注释,我想将这个相同的“默认过滤器”应用于jOOQ查询。当我将jOOQ查询传递给nativeQuery(org.jOOQ.query query,Class

这就是我尝试过的:

private static <E> SelectConditionStep<Record> applyDefaultFilters(Class<E> type, SelectConditionStep<Record> query)
    {
      if (BaseOrganizationModel.class.isAssignableFrom(type)) {
        query
            .getQuery()
            .addConditions(
                query
                    .getQuery()
                    .asTable()
                    .field("organization_id", Long.class)
                    .eq(currentOrganization().id));
        if (SoftDeletableModel.class.isAssignableFrom(type)) {
          query
              .getQuery()
              .addConditions(query.getQuery().asTable().field("deleted", Boolean.class).eq(false));
        }
      }
      return query;
    }

结果就是这个SQL,不是我想要的,我要它过滤对应的表。

select distinct `EventGroup`.*
from `EventGroup`
where (
  ...
  and `alias_100341773`.`organization_id` = ?
  and `alias_17045196`.`deleted` = ?
)

我想要这个

select distinct `EventGroup`.*
from `EventGroup`
where (
  ...
  and `EventGroup`.`organization_id` = ?
  and `EventGroup`.`deleted` = ?
)

这有可能吗?如果没有,还有什么其他可能的路线?(除了明显的将表格传递给函数之外)

共有1个答案

南宫凯康
2023-03-14

jOOQ 3.16引入了一个新的实验性(截至3.16)查询对象模型API,可以遍历。

在任何Select上,只需调用Select.$from()即可访问包含的表列表的不可修改视图。

每次您尝试修改现有查询时,请问自己,是否有更优雅的方法使用更实用、更不可变的方法进行动态SQL?与其将额外的谓词附加到查询中,为什么不从函数中生成谓词?

private static Condition defaultFilters(Class<?> type, Table<?> table) {
    Condition result = noCondition();

    if (BaseOrganizationModel.class.isAssignableFrom(type)) {
        result = result.and(table.field("organization_id", Long.class)
                                 .eq(currentOrganization().id));

        if (SoftDeletableModel.class.isAssignableFrom(type))
            result = result.and(not(table.field("deleted", Boolean.class)))
    }

    return result;
}

现在,当您构建查询时,您可以添加过滤器:

ctx.select(T.A, T.B)
   .from(T)
   .where(T.X.eq(1))
   .and(defaultFilters(myType, T))
   .fetch();

如果你真的想改变你的查询(例如,在一个用于所有查询的实用程序中),那么转换方法可能更合适。有不同的方法来实现这一点。

使用视图

一些RDBMS可以访问视图中的会话变量。在Oracle中,您可以在视图内部的organization_id中设置一些SYS_CONTEXT变量,然后只查询(可能是可更新的)视图,而不是直接查询表。不幸的是,MySQL不能做等效的事情,请参阅MYSQL中是否有与ORACLESYS_CONTEXT('USERENV','OS_USER')等效的东西?

我在这篇博文中描述了这种方法。这种方法的优点是您永远不会忘记设置谓词(您可以使用CI/CD测试验证您的视图源代码),如果您忘记设置会话上下文变量,视图将不会返回任何数据,因此它是一种非常安全的方法。

AND CHECK OPTION子句一起,您甚至可以防止插入错误的organization_id,从而提高安全性。

在jOOQ中使用VisitListener

这是在jOOQ中实现这一点的最强大的方法,这正是您想要的,但对于所有边缘情况来说,这也是一种非常棘手的方法。请参阅这篇关于在jOOQ中实现行级安全性的文章。从jOOQ 3.16开始,将有更好的方法通过https://github.com/jOOQ/jOOQ/issues/12425.

注意,它不适用于不使用任何jOOQ查询部分的普通SQL模板,也不适用于基于JDBC的查询或系统中可能存在的其他查询,因此请小心使用这种方法,因为可能会从其他组织泄漏数据。

当然,您也可以在JDBC层上实现这一步骤,使用jOOQ的ParsingConnection或ParsingDataSource,这样您还可以拦截第三方SQL并附加谓词。

这可以适用于所有DML语句,包括UPDATEDELETE。对于INSERT来说有点困难,因为您必须将INSERT... VALUES转换为INSERT... SELECT,或者如果有人想插入错误的organization_id,则抛出异常。

在jOOQ中使用ExecuteListener

与上面的VisitListener方法相比有点黑客化,但通常更容易正确,只需正则表达式将所有语句的WHERE子句替换为WHERE organization\u id=…和ExecuteListener中的。

为了安全起见,您可以拒绝没有WHERE子句的所有查询,或者做一些额外的技巧,在正确的位置添加WHERE子句,以防没有。

使用jOOQ与Hibernate的过滤器等效

jOOQ与Hibernate的过滤器等价于表。其中(条件)子句。这不是完全等效的,您必须防止直接访问代码库中的T,并确保用户仅通过用T替换T的方法访问T。其中(defaultFilters(myType,T))。

这种方法目前失去了表的类型安全性,请参阅:https://github.com/jOOQ/jOOQ/issues/8012

 类似资料:
  • 我有两个IP的主节点和工作节点?我需要使用这些部署一些服务。我对kubernetes一无所知,什么是主节点和工作节点? 我该如何开始?

  • 我正在研究Blob,我注意到当你有一个ArrayBuffer时,你可以很容易地将它转换成Blob,如下所示: 我现在的问题是,有没有可能从一团变成一团?

  • 我遵循了下一个教程:http://cwbuecheler.com/web/tutorials/2014/restful-web-app-node-express-mongodb/ 过了几天,我就把一切都做好了,但是更新用户数据库是读者自己的事。 我已经编辑了翡翠模板,并添加了一些javascript,用于更新链接上的点击事件。我甚至可以从列出的测试用户那里检索用户ID。用警报测试了这个,可以了。

  • 如何从(在清单中)使用java?

  • 问题内容: 因此,我试图在Eclipse中的已编译.class文件上运行“ javah”工具,但我不知道如何执行此操作。我发现的示例只是简单地说了“在类上运行javah …”,但我真的不知道在Eclipse中哪里可以找到这样的命令行。 如果有人可以给我一套愚蠢的证明说明,让我在Eclipse中完成这项工作,我将不胜感激。 谢谢 :) 问题答案: AFAIK Eclipse在默认情况下不集成java

  • 问题内容: 我一直在尝试了解如何开始编写和运行JUnit测试。 当我阅读本文时: http://junit.sourceforge.net/doc/testinfected/testing.htm 我到达页面的中间,他们写道:“ JUnit带有图形界面来运行测试。在窗口顶部的字段中输入测试类的名称。按Run(运行)按钮。” 我不知道如何启动该程序。我什至不知道它在哪个包中,或者您如何从IDE运行库