在Ecto迁移中使用仓库 [英] Using a Repo in an Ecto migration

查看:80
本文介绍了在Ecto迁移中使用仓库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我进行了Ecto迁移,我想修改一些列,但同时还要迁移一些数据。例如:

I've got an Ecto migration where I'd like to modify some columns but also migrate some data. For example:

import Ecto.Query

defmodule MyApp.Repo.Migrations.AddStatus do
  alter table(:foo) do
    add(:status, :text)
  end

  foos = from(f in MyApp.Foo, where: ...)
         |> MyApp.Repo.all

  Enum.each(foos, fn(foo) ->
    # There's then some complex logic here to work 
    # out how to set the status based on other attributes of `foo`
  end)
end

现在,这里的问题是,通过调用 MyApp.Repo.all ,迁移实际上使用了一个单独的数据库连接来连接 alter表... 语句(编辑:此假设为假,请参见接受的答案)。因此,没有 status 列,因此整个迁移过程变得很糟!请注意,我们使用的是 postgres 数据库,因此DDL语句具有事务性。

Now, the problem here is that by calling MyApp.Repo.all the migration essentially uses a separate database connection to the one which the alter table... statement used (EDIT: This assumption is false, see the accepted answer). Consequently, no status column so the whole migration blows up! Note, we're using a postgres database so DDL statements are transactional.

可以将其作为两个单独的迁移或 mix 任务来设置数据,仅将迁移留给架构更改,但不想这样做以确保数据一致性。

I could do this as two separate migrations or a mix task to set the data, leaving the migration only for the schema change, but would prefer not to in order to ensure data consistency.

有人想到如何以这种方式对 MyApp.Repo 查询使用相同的数据库连接吗?

Any thoughts on how to use the same database connection for MyApp.Repo queries in this manner?

编辑:请注意,我正在处理少量数据,在我的用例中可以接受停机时间。如果不是这种情况,请参见下面的José响应,以获得一些好的建议。

EDIT: Note, I'm working on a small set of data and downtime is acceptable in my use case. See José's response below for some good advice when this is not the case.

推荐答案

您可以在迁移中执行当前待处理的更改通过调用 Ecto.Migration.flush / 0 。之后的任何代码都将具有状态字段。

You can execute the current pending changes in a migration by calling Ecto.Migration.flush/0. Any code after that will have the status field available.

defmodule MyApp.Repo.Migrations.AddStatus do
  alter table(:foo) do
    add(:status, :text)
  end

  flush()

  foos = from(f in MyApp.Foo, where: ...)
         |> MyApp.Repo.all

  ...
end

这篇关于在Ecto迁移中使用仓库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆