如何使用 laravel 迁移和种子正确处理数据库数据更改
Posted
技术标签:
【中文标题】如何使用 laravel 迁移和种子正确处理数据库数据更改【英文标题】:How to properly handle database data changes with laravel migrations and seeds 【发布时间】:2016-07-04 04:57:35 【问题描述】:我有我的迁移文件,它为数据库创建初始架构,我有我的种子文件,它使用随机数据和设置类型填充初始架构。
我对迁移和种子的理解是,每当有新团队成员加入时,他都可以运行它们并跟上所有数据库更改和产品工作所需的数据,此外,您可以应用更改通过运行迁移文件到 stg 和 prod。
但是,随着我的项目的推进,新类型的数据已经出现,应用它们的唯一方法是创建一个将插入到数据库中的迁移。
我遇到的问题是工匠使用迁移和种子的方式是它首先运行所有迁移,然后运行所有种子,我似乎没有办法指定顺序他们应该在其中运行。因此,如果我运行 migrate:refresh --seed 我会出错,因为它应用了最新的迁移,它会插入新数据(可能会或可能不会,取决于插入种子中的类型)种子插入了自己的数据。
我们尝试的一个解决方案是更新种子,并在应用更改插入数据的迁移之前进行检查,但这变得非常难以维护。
对于这种情况,迁移和种子的预期用途是什么?
更新 为了更清楚地说明: 假设我有一个创建用户的迁移: 用户:id, name, type 而且我有创建用户的种子。
我同时运行这两个,我有一个包含一堆用户的用户表。
时间过去了,我们决定需要一个 user_types 表。 创建了一个迁移,它将创建新表,并填充新用户类型的数据并更新以匹配当前 user.type 到 user.type_id。
Devs 运行迁移并且他们的数据库都是最新的。
一个新的开发者加入了团队。他负责迁移。然后是种子。 它坏了。
现在,如果我们更新种子以匹配最新的,我们将遇到 user_types 表的重复数据。为了避免这种情况,我们需要在迁移中添加某种防御性代码,以便在没有数据时不运行任何东西,如果有则更新。
问题是,这是使用迁移的正确方法吗?如何在无需重新运行种子的情况下将数据更改推送给所有开发人员?
【问题讨论】:
也许我理解错了,但我没有想到数据库结构可以或应该依赖于实际数据的场景。它们是偶然的外键问题,您需要在创建子数据之前创建父数据吗? 我用一个场景更新了描述 播种机应该重新运行。每个播种机都有一个Model::truncate()
作为起点。
【参考方案1】:
从你的解释,我想我明白了。
播种者应该做的第一件事是删除所有内容,因此您始终从一个空数据库开始,至少在播种者应该关注的地方。
我还会仔细查看文档 https://laravel.com/docs/5.2/seeding,特别是“使用模型工厂”部分。
public function run()
factory(App\User::class, 50)->create()->each(function($u)
$u->posts()->save(factory(App\Post::class)->make());
);
在这种情况下,您会做类似的事情,除了您从顶部开始,对您来说是 user_types
,然后对于它创建的每种类型,它会生成您需要的任意数量的用户。这似乎与您当前的流程有点不同,听起来您每个表都有一个种子文件。
这样,您可以处理父/子关系并在代码中非常清晰,并且将来添加其他项目非常容易。此外,因为每次播种机运行时您基本上都是从头开始,您可以确定这对新的和现有的开发人员都适用。
【讨论】:
我想,在为已播种的用户在迁移中插入或修改数据之前,我仍然需要进行检查,对吧?【参考方案2】:我认为迁移不应该依赖于种子中的任何数据。种子应该期待最新的迁移模式。因此,每当您的架构发生变化时,您都应该相应地更新种子并执行 migrate:fresh --seed。至少,这就是我正在做的。
既然你已经这样做了,我想知道是什么让它对你来说是一个“麻烦的过程”。能详细点吗?
【讨论】:
是的,问题是,我们希望迁移帮助我们避免这样做:每次进行新更改时都必须刷新。这样我们就可以在 stg 甚至 prod 上运行迁移,以添加新类型、修改现有表等。 好吧,你假设永远不要在生产数据库中播种。播种仅用于测试。所以,如果你在种子中有一些东西应该在发布后在生产中创建,我打赌你应该把它移到迁移中。 @user3158900 添加了一个很好的答案,阐明了播种前擦除的部分内容。以上是关于如何使用 laravel 迁移和种子正确处理数据库数据更改的主要内容,如果未能解决你的问题,请参考以下文章