保存 HQL 或 EJB QL 的数据结构

发布于 2024-08-07 11:39:50 字数 347 浏览 9 评论 0原文

我们需要生成一个相当复杂的动态查询构建器来动态检索报告。我们对哪种数据结构最好有点摸不着头脑。

它实际上只不过是保存一个 selectParts 列表、一个 fromParts 列表、一个 where criteria、order by、group by 的列表,以实现持久性。当我们开始考虑连接,尤其是外连接、having 子句和聚合函数时,事情开始变得有点模糊。

我们现在首先构建界面,并尝试尽可能超前地思考,但当我们发现结构的局限性时,肯定会进行一系列重构。

我在这里发布这个问题是希望有人已经提出了一些我们可以作为基础的东西。或者知道一些图书馆或类似的图书馆。在我们下周深入实施之前,最好能获得一些关于潜在问题的提示或提示。

We need to produce a fairly complex dynamic query builder for retrieving reports on the fly. We're scratching our heads a little on what sort of data structure would be best.

It's really nothing more than holding a list of selectParts, a list of fromParts, a list of where criteria, order by, group by, that sort of thing, for persistence. When we start thinking about joins, especially outer joins, having clauses, and aggregate functions, things start getting a little fuzzy.

We're building it up interfaces first for now and trying to think as far ahead as we can, but definitely will go through a series of refactorings when we discover limitations with our structures.

I'm posting this question here in the hopes that someone has already come up with something that we can base it on. Or know of some library or some such. It would be nice to get some tips or heads-up on potential issues before we dive into implementations next week.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

近箐 2024-08-14 11:39:50

我过去曾做过几次类似的事情。我想到了一些更重要的事情。

  • where 子句是最难正确的。如果你把事情分成我所说的“表达式”和“谓词”,它就会变得更容易。
  • 表达式 - 列引用、参数、文字、函数、聚合(计数/总和)
  • 谓词 - 比较,如、之间、in、is null(谓词将表达式作为子项,例如 expr1 = expr2。然后您还可以使用复合词,例如 and/ 。
  • 正如您可以想象的,整个 where 子句是一棵树,其根部有一个谓词,下面可能有子谓词,最终以叶子处的表达式结尾。
  • 要构建 HQL,您需要遍历模型(通常是深度优先) )。我使用了访问者,因为我需要出于其他原因遍历我的模型,但如果您没有多个目的,您可以将渲染代码直接构建到模型中,

例如,如果您有

"where upper(column1) = :param1 AND ( column2 is null OR column3 between :param2 and param3)"

那么树就是

Root
- AND
  - Equal
    - Function(upper)
      - ColumnReference(column1)
    - Parameter(param1)
  - OR
    - IsNull
      - ColumnReference(column2)
    - Between
      - ColumnReference(column3)
      - Parameter(param2)
      - Parameter(param3)

那么您遍历树。深度优先并在备份时合并 HQL 的渲染位,例如,upper 函数期望渲染一段子 HQL,然后生成

“upper( " + childHql + " )"

并将其传递给它的父级。 Between 需要三个子 HQL 片段。

  • 然后,您可以在 select/group by/order by 子句中重新使用表达式模型

  • 您可以如果您愿意,只需存储选择并在查询构造扫描之前扫描聚合即可跳过存储组。如果有一个或多个,则只需将所有非聚合选择表达式复制到分组依据中。

  • From 子句只是表引用的列表 + 零个或多个连接子句。每个连接子句都有一个类型(内/左/右)和一个表引用。表引用是表名 + 可选别名。

另外,如果您想要解析查询语言(或任何真正的语言),那么我强烈推荐 ANTLR。学习曲线相当陡峭,但有很多语法示例可供查看。

HTH。

I've done something similar couple of times in the past. A couple of the bigger things spring to mind..

  • The where clause is the hardest to get right. If you divide things up into what I would call "expressions" and "predicates" it makes it easier.
  • Expressions - column references, parameters, literals, functions, aggregates (count/sum)
  • Predicates - comparisons, like, between, in, is null (predicates have expression as children, e.g. expr1 = expr2. Then you also having composites such as and/or/not.
  • The whole where clause, as you can imagine, is a tree with a predicate at the root, with maybe sub-predicates underneath eventually terminating with expressions at the leaves.
  • To construct the HQL you walk the model (depth first usually). I used a visitor as I need to walk my models for other reasons, but if you don't have multiple purposes you can build the rendering code right into the model.

e.g. If you had

"where upper(column1) = :param1 AND ( column2 is null OR column3 between :param2 and param3)"

Then the tree is

Root
- AND
  - Equal
    - Function(upper)
      - ColumnReference(column1)
    - Parameter(param1)
  - OR
    - IsNull
      - ColumnReference(column2)
    - Between
      - ColumnReference(column3)
      - Parameter(param2)
      - Parameter(param3)

Then you walk the tree depth first and merge rendered bits of HQL on the way back up. The upper function for example would expect one piece of child HQL to be rendered and it would then generate

"upper( " + childHql + " )"

and pass that up to it's parent. Something like Between expects three child HQL pieces.

  • You can then re-use the expression model in the select/group by/order by clauses

  • You can skip storing the group by if you wish by just storing the select and before query construction scan for aggregate. If there is one or more then just copy all the non-aggregate select expressions into the group by.

  • From clause is just a list of table reference + zero or more join clauses. Each join clause has a type (inner/left/right) and a table reference. Table reference is a table name + optional alias.

Plus, if you ever get into wanting to parse a query language (or anything really) then I can highly recommend ANTLR. Learning curve is quite steep but there are plenty of example grammars to look at.

HTH.

征棹 2024-08-14 11:39:50

如果您需要 EJB-QL 解析器和数据结构,EclipseLink(以及它的几个内部类)有一个很好的选择:

JPQLParseTree tree = org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser.buildParserFor(" _the_ejb_ql_string_ ").parse();

JPQLParseTree 包含所有数据。

但是从修改后的 JPQLParseTree 生成 EJB-QL 是您必须自己做的事情。

if you need EJB-QL parser and data structures, EclipseLink (well several of it's internal classes) have good one:

JPQLParseTree tree = org.eclipse.persistence.internal.jpa.parsing.jpql.JPQLParser.buildParserFor(" _the_ejb_ql_string_ ").parse();

JPQLParseTree contains the all the data.

but generating EJB-QL back from modified JPQLParseTree is something you have to do yourself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文