如何在持久性中具有模块间/包间外键约束

Posted

技术标签:

【中文标题】如何在持久性中具有模块间/包间外键约束【英文标题】:How to have inter-module / inter-package foreign key constraints in Persistent 【发布时间】:2018-03-02 21:31:22 【问题描述】:

由于我们的数据库中有很多模型,其中许多都相当独立地运行,我们决定在不同的模块中定义它们。然后,我们有一个 migrateAll 函数,它以串行方式运行每个迁移。似乎我们这样做会导致 Persistent 不在模型之间创建外键约束,但我真的希望这些约束存在。

作为部分修复,我们可以将它们全部放入同一个模块中,但我们还有一个单独的包,它依赖于第一个包,它在顶部创建更多模型,同样带有一些外键。当它们之间确实只有单向依赖关系时,我们不得不将这些包合并为一个,这对我们来说真的很痛苦。

是否有任何方法可以跨模块创建外键约束?也许通过这样做,如果您迁移具有外部外键约束的模型,也会运行外部模型的迁移。避免需要按依赖顺序对迁移进行排序。

也有可能没有创建外键的原因与此设置无关,但我似乎找不到其他人遇到同样的问题,所以我假设上述是原因。

对于 MCVE:

module Foo where

share [mkPersist sqlSettings, mkMigrate "migrateFoo"] [persistLowerCase|
Foo
    name String
|]
module Bar where

import Foo

share [mkPersist sqlSettings, mkMigrate "migrateBar"] [persistLowerCase|
Bar
    name String
    foo FooId
|]
module Models where

import Foo
import Bar

migrateAll :: Migration
migrateAll = migrateFoo *> migrateBar

运行migrateAll 会做我想做的一切,除了在Bar.foo 字段上创建外键约束。如何在保持我想要的模块化的同时获得外键约束?

【问题讨论】:

MCVE 会大大改善这个问题。 @DanielWagner 完成,谢谢! 我觉得这里添加的API解决了这个问题github.com/yesodweb/persistent/pull/791 @MaxGabriel 谢谢!唯一的问题是,找出文件系统上库依赖关系的最终位置并非易事,所以我真的需要一种方法来import 我也在构建外键的表,而不仅仅是在编译时从文本文件中读取。这是因为包的依赖项实际上创建了它们自己的表,我需要迁移这些表并创建外键。 【参考方案1】:

由于persistent-2.13.0,现在可以使用mkPersistWith。在你的情况下:

module Foo where

share [mkPersist sqlSettings, mkEntityDefList "fooDefs"] [persistLowerCase|
Foo
    name String
|]

请注意,我使用mkEntityDefList 导出TemplateHaskell 生成的EntityDefs 以​​在Bar 中使用它们:

module Bar where

import Foo

share [mkPersistWith sqlSettings fooDefs, mkEntityDefList "barDefs"] [persistLowerCase|
Bar
    name String
    foo FooId
|]

还要注意,我不使用帮助程序 mkMigrate(目前使用它不适用于 mkPersistWith,因为它会引发运行时错误)。现在可以使用migrateModels 进行迁移:

module Models where

import Foo
import Bar

migrateAll :: Migration
migrateAll = migrateModels (fooDefs ++ barDefs)

这会正确地创建ForeignRefs,甚至更新旧的丢失。

【讨论】:

以上是关于如何在持久性中具有模块间/包间外键约束的主要内容,如果未能解决你的问题,请参考以下文章

如何更新具有外键约束的数据库?

删除具有外键约束且无级联删除 SQL 的行

带有连接表的 MySQL 外键约束(具有相同外键约束时出错)

在一个命令中添加具有外键约束的新列

在SQL中如何创建外键约束?

数据库中为什么不推荐使用外键约束