sql 数据操作操作的基于集合的建模代码列表

Modeling set-based code-listings of sql data manipulation operations

LINQ 等技术在描述关系数据查询方面做得很好,其类型包括 IQueryableIGroupingIOrderedQueryable 建模 投影selectionsaggregationssorting 等。关系代数中的这些概念让我们在一台机器上以一种语言传达相当任意的查询,并在另一台机器上以不同的语言 (~sql) 执行它。

如果能够对更复杂的多部分查询甚至涉及 INSERTs、UPDATEs 和 [=16 的数据操作命令执行相同的操作,那就太好了=]s 可以 描述 完整操作,而无需首先 retrieving/hydrating 应用层数据的开销,这是典型的对象关系映射器或 ORM。

在应用程序中,我们可以描述这样的操作 删除所有 Customers(以及他们的 Orders)最近的 Order 早于 2 年 (而且,假设没有为该关系启用级联删除)。这当然比说 ADO 和 t-sql 脚本更有效,但不能在 ORM 中完成,因为没有选择、传输、水合和跟踪应用程序层中的数据以及可能发出单独的删除命令的开销. (也许 ORM 有一些优化可以在某些情况下更有效地做到这一点,但通常 AFAIK 他们不能)发布 t-sql 脚本的问题当然是语句中没有类型检查,也没有类型检查。对于任何参数或 return 数据。

除了减少运行时处理和网络聊天开销之外,能够对这些任意命令进行建模以进行远程执行的一个惊天动地的优势是,可以在应用程序层中编码和注册域范围的不变量,然后可以与任何临时命令一起自动发出。

我们可能有一个愚蠢的域不变量 A对于所有 Customers,每个 Customer[=88= 的总和] 的 订单 价格 不能超过 10,000,000.00 美元,除非 whoa 位为 1和另一个愚蠢的域不变量 BFor all Customers, lastName 不能包含超过三个下划线(尽管这些可能可以通过数据库引擎本身的检查约束或触发器的本机机制来强制执行)。然后当我们发出命令更新现有的 Order's price 时,系统可以通过静态分析知道可能违反不变 A作为命令的结果,不变量 B 不能,因此系统会在原始命令之后发出一些 A 的断言。整个发出的脚本将被包装在一个事务中(如果断言失败则回滚)并且不变量可以自动缩小以仅针对特定的 Customer's 集合断言规则 Orders 而不是不必要地重新检查 all Customers' 总数。我相信这种优化的、集中的、DRY 的业务规则 encoding/enforcement 在今天的产品中是不可能的。

为了实现这种潜力,我认为我们需要一个代数(超越 SELECT 的关系代数)来描述插入、更新和删除的任意数据操作(统称为 DML) 甚至中间计算值之类的东西,比如用于计算的临时表,在 t-sql 中表示为多语句列表。

不幸的是,我一直无法找到关于将 DML 形式化为代数、能够对其建模或此类元编程的研究。尽管 Tutorial-D 和 jOOq 似乎为讨论提供了一些东西——我只是不知道如何提取它。你能澄清一下吗?


一些我认为有价值的讨论,但我想避免用它填满评论:

Are you suggesting that domain models aren't a good fit to protect invariants and establishing transactional boundaries? The invariants you mentioned aren't hard to protect using a proper domain model. What problem are you trying to avoid exactly?

– plalx

As I understand it, large domains in typical ddd require bounded contexts to avoid having to hydrate large subsets of the data into the application layer for validation. I am trying to avoid that overhead. Also, domain invariants must be non-trivially restated for each bounded context, which is error-prone. By modeling the operations for remote execution, we get smarter/smaller/faster/more correct code.

In some core library, the domain could be modeled and the invariants registered. Then consumers of that library, such as for a web service, could then construct type-checked descriptions of arbitrary operations without explicit consideration for bounded contexts or particular invariants. The domain core offers to its consumers "this is the full range of what you can do over this domain" and (perhaps) the service code offers to its clients "these are the exact features we're offering".

– uosɐſ

I'm not sure if you understood correctly what a Bounded Context is and how they might communicate with each-other. "Also, domain invariants must be non-trivially restated/maintained for each bounded context which is error-prone" There's usually just one context that have data ownership and that context shall be responsible for invariants involving it's own data. For instance, imagine a company that sells goods on Internet. They might have an Inventory context where products gets maintained and a Shopping context that listen to newly available products from the Inventory.

– plalx

I'm not very much arguing against current ddd techniques, so I'm not choosing excellent examples against them. I'm more interested in this alternative arrangement which I intuit would be more natural and advanced than current ddd techniques. I've seen data models that are extremely intertwined and don't offer obvious boundaries (perhaps poorly designed, OK). I expect that this way could be boundaryless AND more performant.

– uosɐſ

If there was a rule that a Product name couldn't contain the word "propaganda" it would be enforced only in the Inventory context. If we were to duplicate invariants of every contexts in every other contexts it would indeed become a maintenance nightmare.

– plalx

But you plausibly might have a bounded context centered on Customers and a second bounded context centered on Orders. And maybe the ,000,000.00 Limit I mentioned is made to be a column in Customer (and therefore variable), so this business rule can be violated in two ways: either by dropping that Limit on Customer or increasing totals in Order. So non-trivially reciprocal rules must check for violations in either bounded context depending on the change. Our system could decide to skip the assertion if Prices and Limits aren't changed, which would be pretty slick, no? In the traditional ddd, you might also need some optimized variants for bulk manipulations (Add an Order of 00 to every Customer) which could be automatically derived by our new system.

– uosɐſ

虽然看起来不太可能,但您 不需要 的一件事是 "something beyond" 关系代数。这根本不是一个理论问题,而是一个想象力和工程问题。您正在谈论的问题跨越多个领域:编程语言、库支持和 DBMS。它可以完成(并且应该)。但首先,它需要被普遍理解为现实的和可取的,而我们还没有做到这一点。

就代数而言,缺少的只是作业。如果您读过 Date 的 Third Manifesto,您可能还记得 insert/update/delete 只是赋值的变体:

S += f(R)        -- insert
S += f(R) - g(S) -- update
S -= f(R)        -- delete

(Python 在其标准库中使用 set class 很好地证明了这一点,顺便说一句,除了你没有得到开箱即用的元组集运算符。)

所以这不是理论问题;代数很好。而且您也不是纯粹询问语法。在我看来,您想要的是一个 DBMS,您可以 功能性地 操作它,而无需 SQL 和 SQL 生成器作为中介。如果数据库中的 tables 在编程语言中显示为变量,并且有一个支持 select 的关系代数库(针对该语言),那岂不是很好? 项目加入

就此而言,为什么不将关系运算符合并到适当的语言中呢?为什么在关系理论发明 40 年后,它的使用仅限于数据库?事实上,几十年来,这一直是数据库社区的遗憾。尽管它已经完成了——cf。例如,Datalog——我们近年来看到的大量新语言一直没有table延续不支持集合论操作的 C 传统。

不过,碰巧的是,仅仅将关系和关系运算符内置到语言中是不够的。编程语言通常希望定义它们的变量,并排他性地拥有它们。这实际上是编程语言的 定义 :定义和操作内存块的东西,其生命周期受程序执行的限制。有趣的数据通常从 "out there" 的某个地方开始,而不是在程序内存中。

所以,您真正想要的是操纵数据 "in the database" ,就好像 那些 table 是程序变量(也称为 action at a distance),然后是一些超级方便、理想情况下透明的方法将结果移动到程序内存中。就像,哦,作业。要在那个方向取得任何进展,您需要 DBMS 的合作。

如今,要与典型的 DBMS 交互,您需要用它的语言(通常 SQL)来表述您的问题,然后将输出逐行提取到程序内存中。这是一个 I/O 模型:写入字符串,读取结果。要将 I/O 从编程模型中移除,您需要一个不同的 API,更像是 RPC。如果编程语言和 DBMS 使用相同的数据模型(关系)和函数(关系代数)和数据类型,那么你就有机会同时操作远程和本地数据一样的方法。

这就是套房:

  • 关系和关系操作的语言支持
  • 本地和机外变量的语言识别
  • DBMS 支持以编程方式公开 table 定义,这样 compiler/interpreter 可以 "link" 作为库符号
  • DBMS 支持远程调用关系运算符,逐个函数,而不是逐个语句

您可能已经注意到,在合理的近似值下,没有人尝试执行上述操作。语言设计者普遍忽略集合论和谓词逻辑。 DBMS 供应商——和流行的免费项目——被 SQL 束缚,对修复 SQL 的集合论缺陷或通过逻辑函数 API 暴露他们的系统完全不感兴趣。任何人脑子里想的最远的事情就是开发一组一致的类型和运算符。

那么我们有什么呢? Linc 是跳舞熊的一个很好的例子,从字符串和原始类型中拼凑 SQL,通过管道喷射,并将数据库 table 表达为宿主语言提供的逐行操作.考虑到当今环境的现实,这是一个非常好的节目。但是,正如您的问题所暗示的那样,新鲜感消失了,工作也没有变得更容易。不过,您可能想保留您的机票:根据当前的速度和方向来判断进展情况,您将在同一个座位上再呆 40 年。