ORM 的目的是什么?
使用 ORM 的主要目的是在网络模型(面向对象、图形等)和关系模型之间架起一座桥梁。两种模型之间的主要区别非常简单。是父母指向孩子(网络模型)还是孩子指向父母(关系模型)。
考虑到这种简单性,我相信there is no such thing as an "impedance mismatch" 介于两个模型之间。人们通常遇到的问题纯粹是特定于实现的,如果在客户端和服务器之间有更好的数据传输协议,应该是可以解决的。
SQL 如何解决我们在使用 ORM 时遇到的问题?
特别是,third manifesto 试图通过允许嵌套集合来解决 SQL 语言和关系代数的缺点,这些集合已在各种数据库中实现,包括:
- Oracle(可能是最复杂的实现)
- PostgreSQL(在某种程度上)
- Informix
- SQL Server、MySQL 等(通过 XML 或 JSON“模拟”)
在我看来,如果所有数据库都实现了 SQL 标准 MULTISET() 运算符(例如 Oracle 实现),人们将不再使用 ORM 进行映射(也许仍然用于对象图持久性),因为它们可以直接从内部实现嵌套集合数据库,例如这个查询:
SELECT actor_id, first_name, last_name,
MULTISET (
SELECT film_id, title
FROM film AS f
JOIN film_actor AS fa USING (film_id)
WHERE fa.actor_id = a.actor_id
) AS films
FROM actor AS a
会将所有演员及其电影作为嵌套集合产生,而不是非规范化的连接结果(每部电影重复演员)。
客户端的功能范式
客户端的函数式编程语言是否更适合数据库交互的问题实际上是正交的。 ORM 有助于对象图的持久性,因此如果您的客户端模型是一个图,并且您希望它是一个图,那么您将需要一个 ORM,无论您是否使用函数式编程语言来操作该图。
但是,由于面向对象在函数式编程语言中的惯用性较低,因此您不太可能将每个数据项硬塞到一个对象中。对于编写 SQL 的人来说,投影任意 元组 是非常自然的。 SQL 包含结构类型。每个 SQL 查询都定义了自己的行类型,而无需事先为其分配名称。这与函数式程序员产生了很好的共鸣,尤其是在类型推断很复杂的情况下,在这种情况下,您永远不会想到将 SQL 结果映射到某个先前定义的对象/类。
在 Java 中使用 jOOQ from this blog post 的示例可能是:
// Higher order, SQL query producing function:
public static ResultQuery<Record2<String, String>> actors(Function<Actor, Condition> p) {
return ctx.select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
.from(ACTOR)
.where(p.apply(ACTOR)));
}
与使用某些 ORM 抽象 SQL 语言或使用 SQL 的“基于字符串”的自然特性相比,这种方法导致 SQL 语句的组合性好得多。现在可以使用上述功能,例如像这样:
// Get only actors whose first name starts with "A"
for (Record rec : actors(a -> a.FIRST_NAME.like("A%")))
System.out.println(rec);
基于 SQL 的 FRM 抽象
一些 FRM 尝试对 SQL 语言进行抽象,通常是出于以下原因:
- 他们声称 SQL 不够可组合(jOOQ 反驳了这一点,很难做到正确)。
- 他们声称 API 用户更习惯于“原生”收集 API,例如
JOIN 被翻译成flatMap() 和WHERE 被翻译成filter() 等等。
回答你的问题
FRM 并不比 ORM“更容易”,它解决了一个不同的问题。事实上,FRM 并没有真正解决任何问题,因为 SQL 作为一种声明式编程语言本身(与函数式编程没有太大区别),与其他函数式客户端编程语言非常匹配。因此,如果有任何作用,FRM 只是在 SQL、外部 DSL 和您的客户端语言之间架起了一座桥梁。
(我在jOOQ后面的公司工作,所以这个答案有偏见)