2024 Clojure状态调查中分享您的想法!

欢迎!请查看关于页面以获取更多有关如何使用本页面的信息。

+4投票
工具
编辑

大家好!

我最近决定复制一个中等规模的项目(该项目用Java编写,使用Spring Boot和Hibernate),想知道如何在Clojure中以习惯性方式建模数据、模型和关系?

我认为这不一定必须是对象或ORM,但我确实认为代码中应该有一种数据库或数据规范的表示(这样开发者就可以知道要从数据库中查询什么,并且可以预期从中获得什么)。

那么,我的选项有哪些?

编辑:目前数据库是PostgreSQL

谢谢!

编辑2:感谢大家的回答,它们非常有帮助,我现在肯定能够解决这个问题了!

6个回答

+4投票

选择
 
最佳答案

你将使用什么数据库?

如果你可以选择一种,正如Adrian也提到过的,请认真考虑使用Datomic,因为它拥有简单且高度灵活的数据模型。

如果你不得不使用SQL,最直接的方法是使用next-jdbbc,它会将查询结果以映射列表的形式返回。如果你不需要对数据进行任何复杂的转换,最简单的方法是直接使用Clojure丰富的函数集来访问和操作数据。不必过分担心创建“域对象”。 Clojure Applied 提供了一些有关如何构建域数据的实用建议。

如果你需要进行复杂的转换,一个常见的技巧是将数据进行“归一化”,也就是说,创建一个大的映射,以“域模型名称”作为一级键,以每条记录的ID作为二级键,然后将模型/表的行作为映射列表。这允许你快速获取到不同的数据片段。这种技术也常用于客户端,如果你需要编写单页应用程序(参看 re-framefulcro)。

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

你还可以查看specter,一个用于执行数据转换的领域特定语言(DSL),尽管在我看来它引入了与DataScript类似的复杂性。无论哪种方法对你来说都有效。

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

我现在在手机上,无法详细解释。
但请查看 https://docs.datomic.com/on-prem/schema.html

+1

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

有一个受到Datomic pull api深度影响的SQL库 http://walkable.gitlab.io
它可以帮助您快速构建API。它提供了一种描述您的表之间关系的方式,这样在系统添加越来越多的表时,您的思绪就不会因为记住实现细节而爆炸。

顺便说一下,在我看来,编写Clojure代码的最新惯用方法是数据驱动。

0

我认为对于这个问题没有唯一的正确答案。但我建议您考虑以下内容......您决定使用关系型数据库(我认为这是完全可以的!)......因此,有人可能会说......首先,您的问题与ER建模等有关,而不仅仅是关于Clojure(:-).....

......我的意思是什么?嗯,您已经提到了ORM。当您用Java做Java时,关系世界和OO世界之间的“阻抗/范式不匹配”,往往会导致大量杂乱和无头绪等问题。

好吧...但是对于使用对象关系映射器(ORM)而言,你需要付出的代价是巨大的(我认为是这样)。比如说,如果你在做事情时不够小心,Hibernate 这样的工具可能会给出非常疯狂的事情/查询...例如,当你天真地获取某种树结构时,生成的 SQL 可能会很荒谬...显然,Hibernate 非常强大...你可以集成非常复杂的缓存等等等等...但是...要想用得好好/正确地使用 Hibernate 并非易事/直接的事...我觉得。

所以...即使是做 Java,我建议首先考虑 Spring JDBC 数据访问...因为...正如我所说...JPA 肯定会带来不少复杂性...(因此,问问自己你是否真的需要 JPA)

...无论如何...我想说的是...关系数据库很棒...SQL 很棒...PostgreSQL 也很棒!!!许多编程语言的麻烦在于与关系技术交互往往非常痛苦...因此,你需要构建各种工具,如 ORM 等,以使你的生活更容易忍受...(所以我们谈论的是治疗方法,而不是治愈方法)

...现在,我想说的是,使用 Clojure 相比之下,整个不匹配问题要轻微得多,因为 Clojure 不是围绕 Person 等类构建的,而是你有一些强大的集合,你就可以出发了 :-)...

...所以让我们来具体谈谈...我已经使用 Clojure(script) 创建了这个闪卡 SAP...

...现在...有很多事情我不太满意...例如,我真的想从 Bootstrap 转到 Bulma 等...这是我做的第一个非平凡的 Clojure 项目...因此,显然我犯了很多错误...我会尽快尝试重构/改进 things...然而,主要的观点是我最不担心的是 PostgreSQL / RDBMS 部分...

....我用 luminus 模板设置 PostgreSQL 项目...这个设置包括 hugsql(拥抱 SQL 的 Clojure 库)....然后你可以做你的 dd l / 模式事宜...你的 PostgreSQL 查询...存储过程等等...以一种完全独立于任何应用程序编程语言的方式进行...只需使用你的 PostgreSQL 工具/知识即可...这有多么伟大!!!!...另外,比如说,如果我想从 Clojure 切换到 Java / Node 等等...我的整个数据库/持久层东西可以基本上保持原样...因为使用 hugsql 你做的就是 SQL...再加上非常少元配置的东西,你将其放入注释中...通过这些注释,你会得到可以运行查询的 Clojure 函数...你可以将这些 prepared 语句的参数以 map 的形式传递...并得到一个 map 的输出,一个记录或 n 个记录的记录序列...以及 nil,如果你没有记录的话,我想。

在进行转换等操作时,你拥有所有基本的但强大的Clojure函数,它们使处理映射和序列变得轻而易举。另外,总会有一些类型转换的内容,例如从PostgreSQL转换为Java,从Java转换为JavaScript。但是,如果你使用Luminus,你将能够直接获得这些辅助工具。例如,在我开发的闪卡应用中,有很多时间戳(例如你何时回答了某张卡的答案,何时留言等)。而日期类型一直以来都颇具挑战性——java.sql、java.util、joda等。但在开发这个应用时,我真的不用为这些担心,因为Luminus会为你处理一切。同样,使用优秀的Clojure(脚本)时间库(https://github.com/dm3/clojure.java-time / https://github.com/andrewmcveigh/cljs-time),你可以编写与时间相关的代码,并且这些代码无论在中间件还是前端都会运行良好(...当然有细微的例外...)。另外,Luminus也提供了需要的transit-adapter(不确定是否真的叫这个名字)相关功能!

无论如何,我采用了这“最少即多”的策略,对此我相当满意。无论你对此有何看法,都请随意吧!:-)

0

最近,我将一个诞生于13年前的Java/Hiernate/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

现在有些时间过去了,既然你问的问题一直在出现,我想或许我可以问你,你最终做出了什么决定。另外,情况如何?你学到了最重要的什么教训?如果你再次这样做,你还会想做什么不同的事情吗?

...