请在2024 Clojure现状调查!中分享您的想法。

欢迎!请参阅关于页面,了解有关此内容的一些更多信息。

+4
工具
编辑

大家好!

最近我决定将一个中等规模的Java项目(使用Spring Boot和Hibernate编写)复制到Clojure中。我想知道如何在Clojure中以惯用方式建模数据和模型以及它们之间的关系?

我认为这并不一定应该是“对象”或ORM,但我确实认为应该有一些数据库或数据规范的结构反映在代码中(这样开发者就可以知道应该从数据库中查询什么,并期望查询结果是什么)。

那么,我的选择有哪些?

编辑:目前数据库是PostgreSQL

谢谢!

编辑2:感谢所有人的回答,他们非常有帮助,我一定能解决这个问题!

6 个回答

+4

被选中
 
最佳答案

你将使用哪个数据库?

如果你可以选择的话,正如Adrian也提到的,请你认真地考虑使用Datomic,因为它具有简单且非常灵活的数据模型。

如果你必须使用SQL,最直接的方法是next-jdbc,它将以列表的形式返回查询结果。如果你不需要对数据进行任何复杂的转换, simplest is to simply use Clojure extensive set of functions to access and manipulate the data. 别太担心创建“领域对象”。 Clojure Applied 提供了一些有关如何结构化领域数据的实用建议。

如果你需要做复杂的转换,一个常见的技巧是进行“规范化”数据,基本上创建一个由“领域模型名称”作为一级键,由每条记录的id作为二级键的大映射,然后是模型/表行作为列表的映射。这样,你可以快速获取不同的数据。这种技巧也常用于客户端,如果你需要编写单页应用程序(看看 re-framefulcro)。

DataScript 是一个类似datomic的内存数据库。它的轻量级足以用于服务器和客户端。你定义一个模式,添加你的数据,然后可以执行它之上的数据日志查询和提取,利用其简单灵活的数据模型。因此,即使你使用SQL数据库,你也可以查询一些数据,将结果加载到DataScript中,在内存中进行进一步的操作和查询,然后再写出结果。

你也可以看看 specter,这是一个用于执行数据转换的领域特定语言(DSL),尽管在我的理解中,它创建了DataScript可以避免的复杂性。 Whatever works for you.

我仅补充一点,我们通常使用 clojure.spec 来在代码中描述数据库模式,这样我们就有:1) 文档 2) 验证代码 3) 一种生成测试的随机、符合规范的数据的方法(这样我们就不必模拟数据库)4) 一个“记录系统”,从中可以导出列等的列表——我们使用宏从规范生成CRUD函数。
by
强烈推荐正规化。然而,我认为re-frame人士中并没有这种常见做法。re-frame的wiki中简要提到,但似乎没有人真正使用它 https://github.com/Day8/re-frame/blob/master/docs/FAQs/DB_Normalisation.md
相比之下,正规化是om.next/fulcro的核心部分。
+4
by

我现在正在手机上,所以不能详细解释
但请查看https://docs.datomic.com/on-prem/schema.html

+1
by

首先,正如其他人提到的,学习一些Datomic或Datascript。这将改变你对数据库的看法。

有一个受Datomic pull api深远影响的SQL库 http://walkable.gitlab.io
它可以帮助你快速构建API。它为你提供了描述表格之间关系的方式,所以当越来越多的表格被添加到系统中时,你的大脑不会因为记住实现细节而崩溃。

顺便说一下,我认为编写Clojure代码的最新范式是数据驱动。

0

我认为这个问题没有唯一的正确答案...但是我想建议你考虑以下内容...你决定采用关系数据库(我认为这完全没问题!)...所以有人可能会说...首先,你的问题与ER建模等有关,而不是clojure... :-)...

...我的意思是什么...嗯...你已经提到了ORM...当你用Java开发时,“阻抗/范式不匹配”问题很常见,这通常会导致大量混乱/头疼等问题。

好吧...但是当你使用ORM时,你付出的代价很大(我认为是这样)...比如,如果你不小心,Hibernate就会提出一些最疯狂的东西/查询...例如,当你愚蠢地获取某种树形结构时,生成的SQL可能非常愚蠢...显然,Hibernate真的非常强大...你可以集成非常复杂的缓存等。等等...然而,要做好的Hibernate并不是那么容易/直接...我认为...

所以...即使是在做Java的时候,我也建议首先考虑spring jdbc数据访问...因为...正如我所说的...JPA确实增加了许多复杂性 ...(所以问问自己你是否真的需要JPA...)

...无论如何...我想说的是...关系数据库很好...SQL很好...PostgreSQL很好!!!...许多编程语言的问题是,与关系技术交互通常真的很痛苦...所以你开始构建各种工具,比如ORM等,以使你的生活更易于忍受...(所以在谈论一种治疗方法,而不是治疗方法...)

...现在我想论证的是,与Clojure相比,整个不匹配问题要轻微得多,因为Clojure没有围绕Person等类构建,而是有几个强大的集合,你可以开始使用了 :-)...

...因此,让我们使这更加具体...我已经使用Clojure(script)构建了这个闪卡SAP...

...现在...有很多事情我不太满意...例如,我真的想从bootstrap切换到bulma等...这是我做的第一个非平凡大小的Clojure项目...显然,我犯了很多错误...我将尽力尽快重构/改进事情...然而,主要点是,我最少担心的是PostgreSQL/关系数据库部分...

我使用了 luminus 模板来设置 postgres 项目。这个设置包括 hugsql(拥抱 SQL 的 Clojure 库)。然后你可以进行你的 DDL/模式操作,你的 postgres 查询,存储过程等等。这一切都完全独立于任何应用编程语言。你只需使用你的 postgres 工具和知识。多么伟大啊!另外,比如说我想从 clojure 切换到 java / node 什么的,我的整个数据库/持久层东西几乎可以保持不变,因为使用 hugsql 你实际上只是在做 SQL。再加上非常少的元配置信息,你会在注释里写这些信息,通过这些注释,你可以得到使用查询的 clojure 函数,你可以以 map 的形式向这些预处理语句传递参数,并得到一个记录的 map 输出,或 n 个记录的 map 序列,没有记录时返回 nil。我想是这样的。

进行转换等操作时,你就有所有的基本但强大的 clojure 函数,使得处理 map 和 seqs 变得轻而易举。还有一个小小的类型转换问题,当你从 postgres 转到 java,从 java 到 js 时,但如果你使用 luminus,你会得到那些现成的辅助工具。比如在我的 flashcard 应用中,有很多时间戳(...你何时答对卡片的答案,何时留下评论等等)而日期类型总是很难处理(java.sql, java.util, joda 等)。但在做这个应用时,我根本不需要担心这些问题。luminus 会为你处理这些。另外,你可以用到优秀的 clojure.java-time(https://github.com/dm3/clojure.java-time / https://github.com/andrewmcveigh/cljs-time)。你可以编写与时间相关的代码,它对中间件和前端都适用(...仅有一些小的例外)。(...luminus 也提供了所需要的 transit-adapter?不知道它实际上是否叫这个名字...)的邮件也!

无论如何,我选择了基于 KISS 原则的战略,对此我非常满意。随便你怎么想,:-)

0
by

我最近把一个操作系统从 13 年前的 java/hibernate/MySQL 设计迁移到了 Clojure/Datomic。

我编写了一个库,该库读取 MySQL 表架构,创建一个抽象表规范,然后使用该规范创建 Datomic 架构,并将所有数据迁移到 Datomic。你可以查看它作为灵感的来源(我试图写出通用的代码,但它的使用场景相当紧密地围绕我的用例)
https://github.com/thosmos/mysql-to-datomic

然而,主要的一点是,我创建了自己的抽象数据规范来描述表,列和外键,这样我就有了生成 Datomic 架构的一切所需,而且还可以自动生成 GraphQL 和 EQL API 以及前端 CRUD 数据输入表单(带链接子表单和数据验证),所有这些都来自这个抽象规范。我试图将这个模型定义规范的核心部分压缩到这个小库中
https://github.com/thosmos/domain-spec

这再次紧密地服务于我的用例,但它可能会激发你意识到,在Clojure中,你可以轻松且强大地进行自己的事情,而不必过度依赖库和依赖项。

0

现在已经过去了一些时间,由于你提出的问题一直存在,我想也许我可以问你,你最终是怎么决定的。还有,事情结果如何?你学到了最重要的经验是什么?如果你再这样做,你会想做什么不同的事情?

...