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

欢迎!请参阅关于页面了解更多关于这个站点的信息。

+4
工具
编辑

大家好!

最近我决定在Clojure中创建一个中等规模项目的复制品(该项目是用Java和Spring Boot、Hibernate编写的)。我很好奇如何以惯用的方式在Clojure中建模数据和模型以及关系?

我认为这不一定必须是对象或ORM,但我确实认为代码中应该有某种类型的数据库或数据规范(因此开发人员可以知道应该从数据库中查询什么,并期望查询得到什么)。

所以我有哪些选择?

编辑:目前数据库是PostgreSQL

谢谢!

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

6个答案

+4

被选为最佳答案
 
最佳答案

你将使用哪种数据库?

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

如果您必须使用SQL,最直接的方法是使用next-jdbc,它会返回一个包含地图的查询结果列表。如果您不需要对数据进行任何复杂的转换,最简单的方法是使用Clojure丰富的函数集来访问和操作数据。不必过分担心创建“领域对象”。《Clojure实战》(Clojure Applied)提供了一些关于如何构造领域数据的实用建议。

如果您需要进行复杂的转换,一个常用的技术是“规约”数据,即在顶级键为“领域模型名称”,每个记录的ID作为二级键的大图谱中创建一个,然后以地图列表的形式存储模型/表的行。这允许您快速获取对数据不同部分的操作权。这种方法也常用于客户端,如果您需要编写单页面应用程序(参见 re-framefulcro)。

DataScript是一种类似Datomic的内存数据库。它足够轻量,可以在服务器和客户端使用。您定义一个模式,添加您的数据,然后可以对它进行datalog查询和提取,利用其简单灵活的数据模型。因此,即使您使用SQL数据库,也可以查询一些数据,将结果加载到DataScript中,然后在内存中进行操作和查询,最后输出结果。

您还可以参考specter,一种进行数据转换的自定义语言(DSL),尽管在我看来,它创造的复杂性是DataScript所避免的。任何适合您的都可以。

by
我还要补充说,我们经常使用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

我目前正在手机上,所以无法详细介绍
但是请查看 https://docs.datomic.com/on-prem/schema.html

+1

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

有一个受 Datomic pull api 深入影响的 SQL 库 http://walkable.gitlab.io
它可以帮助你快速构建 API。它提供了一种表达式化的方式来描述你表之间的关系,这样在系统添加更多表格时,你就不会因为 remember 实现细节而感到崩溃。

顺便说一下,我认为目前编写 Clojure 代码的最最新惯用法是数据驱动。

0

我认为对于这个问题的唯一正确答案不存在……但我建议你考虑以下几点……你决定使用关系数据库(我认为那是完全可以的!)……因此可以争辩……首先,你的问题与 ER-modeling 等相关,而不是真正关于 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模板来设置PostgreSQL项目,这个设置包括hugsql(一个拥抱SQL的Clojure库)……然后你可以做你的DDL/模式东西……你的PostgreSQL查询……存储过程等等……以一种完全独立于任何应用程序编程语言的方式……只需使用你的PostgreSQL工具/知识……这有多好!!……另外,比如说我想从Clojure切换到Java/Node等……那么我整个数据库/持久层的东西可以基本上保持原样……因为hugsql你真的只是在做SQL……加上非常少的元配置事情,这些都以注释的形式放在那里……从这些注释中,你会得到你可以用它在中间件和前端运行的Clojure函数……你可以将这些参数以映射表的形式传递给这些预定义语句……并作为单一的记录的映射或n条记录的映射序列或nil返回你的输出……我想是这样的……

……对于执行转换等操作,你有一套基本但强大的Clojure函数,它们可以让地图和大序列变得容易处理……另外,当从PostgreSQL到Java,从Java到JS转换时,总会有一点类型转换的事情……但如果使用luminus,你会得到一些帮助工具……所以例如,在我的闪卡应用中,有很多时间戳……(……你什么时候得到了某个卡的答案……你什么时候留下了评论等等等等……)……并且日期类型一直是棘手的……java.sql,java.util,joda等……但是当做这个应用程序时,我真的不需要担心任何这些事情……luminus会把这一切都为你处理好……另外,使用优秀的clj(script)时间库……( https://github.com/dm3/clojure.java-time / https://github.com/andrewmcveigh/cljs-time )……你可以编写你的时间相关代码,并且在中间件以及前端上都会起作用……(……有一些例外……)……(……luminus还提供了需要的transit-adapter?(不确定是否真的叫这个名字)工具也!!……)

……无论如何……我选择了这个KISS原则为基础的策略,而且我对此相当满意……你想怎么理解就怎么理解吧 :-)

0

我最近将一个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

现在有些时间过去了,因为你问的问题一直不断,我想也许我可以问问你,你最后决定怎么做。事情结果怎么样?你学到了最重要的教训是什么?如果再做一遍,你有什么会不同做的?

...