请在Clojure 2024调研问卷!中分享您的想法。

欢迎!有关如何使用该页面的更多信息,请参阅关于页面。

+4
工具
编辑

大家好!

最近我决定将一个中等大小的项目(用Java Spring Boot和Hibernate编写)在Clojure中进行复制。我想知道如何在Clojure中以惯用方式建模数据、模型和关系?

我认为这不一定必须是 对象 或ORM,但我确实认为应该在代码中反映某种数据库或数据规范(因此,开发者可以知道应该从数据库中查询什么以及期望查询结果是什么)。

那么,我有哪些选择呢?

编辑:目前使用的是PostgreSQL数据库

谢谢!

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

6 个回答

+4

被选中
 
最佳回答

您将使用哪种数据库?

如果您能选择一种数据模型,就像Adrian所说的那样,请严肃考虑Datomic,因为它有一个简单且高度灵活的数据模型。

如果您必须使用SQL,最直接的方法是使用next-jdbc,它会将查询结果以地图的列表形式返回。如果您不需要对数据执行任何复杂的转换,最简单的方法是直接使用Clojure的函数集来访问和操作数据。不用担心创建'领域对象'。《Clojure实用》提供了关于如何构建领域数据的实际建议。

如果您需要进行复杂的转换,一个常见的技巧是对数据进行'规范化',即创建一个以'领域模型名称'为一级键、每个记录的ID为二级键的大地图,然后将模型/表行作为地图列表。这使得您能够快速访问不同的数据块。这种技术在客户端也很常用,如果您需要编写单页应用(请参见re-framefulcro)。

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

您还可以考虑specter,这是一个用于执行数据转换的DSL,虽然在我的想法中,它创建的复杂性比DataScript所避免的要多。Whatever works for you.

by
我只想补充一下,我们经常使用clojure.spec在代码中描述我们的数据库架构,这样我们就有1) 文档 2) 验证代码 3) 一种生成随机、符合规范测试数据的方法(这样我们就不需要模拟数据库) 4) 从中派生列等的“记录系统” 5) 从Specs使用宏生成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。它提供了一种描述您的表之间关系的方法,这样当系统添加更多表格时,您的思维就不会因为记住实现细节而爆炸。

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

0

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

...我的意思是什么...嗯...您已经提到了ORM...由于Java中关系世界和OO世界之间的“阻抗/范式不匹配”,很多时候,这会导致大量的混乱/头痛...等等。

好吧...但是您付出了巨大的代价(我认为)通过采用ORM...也就是说,如果您不慎重,例如Hibernate将提出最疯狂的事物/查询...例如,当天真地获取某种树结构时,生成的SQL可能相当愚蠢...显然Hibernate非常强大...您可以集成非常复杂的缓存等...等等...但是要正确/有效地使用Hibernate并不那么容易/简单...我认为...

所以,即使是在做Java的时候,我也建议首先考虑Spring JDBC数据访问,因为……正如我说的那样……JPA无疑增加了许多复杂性……(因此要问问自己你真的需要JPA吗……)

……不管怎样,我想说的是,关系型数据库很棒……SQL很棒……PostgreSQL很棒!!!许多编程语言的麻烦在于,与关系型技术交互往往非常痛苦,所以你开始构建各种工具,如ORM等,以使生活更加可忍受。(……所以我们在谈论一种治疗,而不是一种治愈……)

……现在我想论证,用Clojure的话来说,整个不匹配问题要小得多,因为Clojure并不是围绕像Person等类构建的,而是你有几个强大的集合,你就可以开业了 :-)……

……所以让我们来具体一点……我已经用Clojure(script)构建了这个闪卡SAP应用程序。

……现在,我对许多事情都感到不太满意……例如,我真的想从Bootstrap转到bulma等类似的东西。这是我做的第一个不太大的Clojure项目……所以显然我犯了很多错误,我将尽可能地尝试重构/改进东西。然而,主要的一点是,我最不担心的是PostgreSQL/RDBMS部分。

……我用luminus模板设置PostgreSQL项目……该设置包括hugsql(一个拥抱SQL的Clojure库)……然后你可以做你的DDL/架构 stuff……你的PostgreSQL查询……存储过程等等。等等。以一种完全独立于任何应用程序编程语言的方式……只需使用你的PostgreSQL工具/知识即可……多么伟大啊!!!……例如,如果你想从Clojure切换到Java/Node等等,好,你的整个数据库/持久层东西基本上可以保持原样……因为使用hugsql,你实际上只是在做SQL……再加上非常少的元配置东西,你可以在注释中放进去……从这些注释中,你会得到可以使用来运行查询的Clojure函数。你可以将这些预处理语句的参数作为map传递,并得到单个记录的map输出,或n记录的map序列,如果没有记录则输出nil。我想。

……在执行变换等操作时,你拥有所有基本但强大的Clojure函数,它们使调整map和seq变得轻而易举。此外,总是会有一些类型转换的东西,当你从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

recently, I moved an app from Java/hibernate/MySQL design to Clojure/Datomic

I wrote a library that reads MySQL table schema, creates an abstract table spec, and then uses the spec to create the Datomic schema and migrates all the data to Datomic. You are welcome to check it out for inspiration (I tried to write it more generally, but it is closely related to my specific case)
https://github.com/thosmos/mysql-to-datomic

However, the main point is that I created my own abstract data spec to describe tables, columns, and foreign keys, so I have all I need not only to generate the Datomic schema, but also to later automatically generate GraphQL and EQL APIs and front-end CRUD data entry forms with linked subforms and data validations. from this abstract spec. I have tried to summarize the essence of this model-definition spec into a minimal library here
https://github.com/thosmos/domain-spec

It is still very focused on my specific use case, but perhaps it will inspire you to realize that in Clojure you can do your own thing quite easily and powerfully without over reliance on libraries and dependencies.

0

some time has passed now, since the question you asked keeps coming up, I thought I might as well ask you what you decided in the end. Also, how did it go? What were the most important lessons learned? If you had to do it again, what would you have done differently?

...