我正在学习如何配置两个表之间的belong_to / has_many关系。我已完成配置,但我不知道调用它的语法。我想获取一个名为 Testbed 的预先存在的表,并将其分配给另一个名为 Group 的表。
这是我写的一个文档来记录这个过程,所以我完成了大部分步骤,直到我现在所在的位置。
在 Phoenix 中,我使用以下命令生成了两个表和相关的 UI 代码:
mix phx.gen.html Testbeds Testbed testbeds name:string
mix phx.gen.html Groups Group groups name:string
命令行提示我为它们添加资源/路由。我照它说的做了。
我跑了:
mix ecto.migrate
测试台迁移
对于测试床,我创建一个迁移文件并添加此字段:
:group_id, references(:groups)
defmodule App.Repo.Migrations.TestbedUpdate do
use Ecto.Migration
def change do
alter table(:testbeds) do
add :group_id, references(:groups) # added
end
end
end
更改组架构我更新组架构。评论的变化
defmodule App.Groups.Group do
use Ecto.Schema
import Ecto.Changeset
alias App.Testbeds.Testbed # Alias!
schema "groups" do
field :name, :string
has_many :testbeds, Testbed # Has many
timestamps()
end
@doc false
def changeset(group, attrs) do
group
|> cast(attrs, [:name])
|> validate_required([:name])
end
end
更改测试台架构
defmodule App.Testbeds.Testbed do
use Ecto.Schema
import Ecto.Changeset
alias App.Groups.Group # Alias
schema "testbeds" do
field :name, :string
belongs_to :group, Group # Belongs to
timestamps()
end
@doc false
def changeset(testbed, attrs) do
testbed
|> cast(attrs, [:name])
|> validate_required([:name])
end
end
我读到我需要合并“预加载”以便我可以读取数据。所以我这样做了:
def list_testbeds do
Repo.all(Testbed)
|> Repo.preload([:group])
end
还有这个
def list_groups do
Repo.all(Group)
|> Repo.preload([:testbeds])
end
当我创建组和测试床并查询它们时,结果如下所示:
%App.Groups.Group{
__meta__: #Ecto.Schema.Metadata<:loaded, "groups">,
id: 3,
name: "FUNK",
testbeds: [],
inserted_at: ~N[2023-09-27 18:13:15],
updated_at: ~N[2023-09-27 18:13:15]
}
%App.Testbeds.Testbed{
__meta__: #Ecto.Schema.Metadata<:loaded, "testbeds">,
id: 1,
name: "Bloop",
group_id: nil,
group: nil,
inserted_at: ~N[2023-09-27 14:04:15],
updated_at: ~N[2023-09-27 18:22:23]
}
我现在需要知道如何编写将测试床分配给组的代码。
创建群组
App.Groups.create_group(%{name: "OINK"})
提交测试平台并分配给团体协会
此代码将创建一个新的测试台并将其分配给 ID 为 1 的组。
group = App.Groups.get_group!(1)
thing = Ecto.build_assoc(group, :testbeds, name: "DUMB")
alias App.{Repo}
Repo.insert(thing)
当您查询该组时,您将看到一个字段名称为 testbeds 并分配有列表的组。该列表包含一个测试床结构。
现在我的问题是,如果我想采用预先创建的测试台并进行与之前的命令相同的关联,我该怎么办?我根本不知道语法,我尝试的所有方法都会导致错误。
我尝试创建一个测试台并手动为其分配一个group_id,如下所示:
App.Testbeds.update_testbed(my_testbed,%{group_id: 2,name: "some-name"})
它不会影响group_id并且它保持为零。
在预先存在的测试台和组之间手动创建关联的正确语法是
使用其 ID 检索要为其分配测试床的组:
group = App.Groups.get_group!(1)
使用 ID 检索要分配给组的测试台:
testbed = App.Testbeds.get_testbed!(1)
建立协会:
thing = Ecto.build_assoc(testbed, :group, group)
使用 Repo.insert 将关联插入数据库:
Repo.insert(thing)
这将创建测试床和组之间的关联,并且测试床中的 group_id 字段将使用组的 ID 进行更新。