- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在我的应用程序中,我有一个方法可以创建一个新的response
。 response
与 player
和 match
都有 belongs_to
关系。
此外,player
和 match
都与 team
有 belongs_to
关系。
看起来像这样:
插入新的response
时,我想验证 player
和 match
是否具有 player_id
和 match_id
变更集中的外键属于同一个 team
。
目前我正在按如下方式实现这一目标。首先,定义一个自定义验证来检查属于外键的记录:
def validate_match_player(changeset) do
player_team =
Player
|> Repo.get(get_field(changeset, :player_id))
|> Map.get(:team_id)
match_team =
Match
|> Repo.get(get_field(changeset, :match_id))
|> Map.get(:team_id)
cond do
match_team == player_team -> changeset
true -> changeset |> add_error(:player, "does not belong to the same team as the match")
end
end
并将验证用作变更集的一部分:
def changeset(model, params \\ %{}) do
model
|> cast(params, [:player_id, :match_id, :message])
|> validate_required([:player_id, :match_id, :message])
|> foreign_key_constraint(:match_id)
|> foreign_key_constraint(:player_id)
|> validate_match_player()
|> unique_constraint(
:player,
name: :responses_player_id_match_id_unique,
message: "already has an response for this match"
)
end
这工作正常,但涉及几个额外的 SQL 查询来查找相关记录,以便获取他们的 team_id
外键来比较它们。
有没有更好的方法来避免额外的查询,也许是使用约束?
最佳答案
我有两个可能的改进:
现在您有两个查询来检查球员和比赛是否属于同一个球队。这意味着两次往返数据库。如果你只使用一个查询,你可以减少一半,例如给定以下查询:
SELECT COUNT(*)
FROM players AS p
INNER JOIN matches AS m
ON p.team_id = m.team_id
WHERE p.id = NEW.player_id AND m.id = NEW.match_id
你会改变你的功能如下:
def validate_match_player(changeset) do
player_id = get_field(changeset, :player_id)
match_id = get_field(changeset, :match_id)
[result] =
Player
|> join(:inner, [p], m in Match, on: p.team_id == m.team_id)
|> where([p, m], p.id == ^player_id and m.id == ^match_id)
|> select([p, m], %{count: count(p.id)})
|> Repo.all()
case result do
%{count: 0} ->
add_error(changeset, :player, "does not belong to the same team as the match")
_ ->
changeset
end
end
我假设您使用的是 PostgreSQL,因此我的回答将与您在 PostgreSQL 手册中找到的内容相对应。
没有(干净的)方法来在执行此操作的表中定义约束。约束只能访问定义它们的表。某些约束只能从它们定义的内容访问列,仅此而已 (CHECK CONSTRAINT
)。
最好的方法是编写一个触发器来验证这两个字段,例如:
CREATE OR REPLACE FUNCTION trigger_validate_match_player()
RETURNS TRIGGER AS $$
IF (
SELECT COUNT(*)
FROM players AS p
INNER JOIN matches AS m
ON p.team_id = m.team_id
WHERE p.id = NEW.player_id AND m.id = NEW.match_id
) = 0
THEN
RAISE 'does not belong to the same team as the match'
USING ERRCODE 'invalid_match_player';
END IF;
RETURN NEW;
$$ LANGUAGE plpgsql;
CREATE TRIGGER responses_validate_match_player
BEFORE INSERT OR UPDATE ON responses
FOR EACH ROW
EXECUTE PROCEDURE trigger_validate_match_player();
前一个触发器在失败时会引发异常。这也意味着 Ecto 将引发异常。你可以看到如何处理这个异常here .
最后,除非您使用类似 sqitch 的东西,否则维护触发器并不容易。用于数据库迁移。
PS: If you're curious, the very dirty way of doing this in a
CHECK
constraint is by defining a PostgreSQL function that basically bypasses the limitation. I wouldn't recommend it.
希望对您有所帮助:)
关于validation - 使用 Ecto,验证具有 2 个不同相关模型的变更集是否具有相同的父模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58889077/
docs状态 run(t, name, module, function, args) :: t when function: atom, args: [any] Similar to run/3,
目前,我正在寻找在运行 mix 任务时添加 SQL 语句日志记录的方法。例如,mix ecto.rollback 和 mix ecto.migrate 等命令输出信息: ... 13:45:53.01
我有两张 table 。 topics的表其中has_many tweets .我的表tweets belongs_to topic . 主题架构: defmodule Sentiment.Topic
今天,和往常一样,我尝试制作 混合 ecto.migrate 在我的 Phoenix 应用程序中,意外地发现了以下错误: warning: could not find repositories fo
我可以使用什么函数来检查关联是否已经加载? 最好检查关联是否已加载,而不是尝试使用它并获取 Ecto.Association.NotLoaded错误。 最佳答案 您可以使用 assoc_loaded?
我在 postgresql 中有一个表,我想用一个随机数更新所有记录的“points”列的值。在其他语言中,我们可以循环遍历所有数据库记录,但我如何使用 ecto 来做到这一点?我试过这个: Rep
在处理具有关联的模型时,加载关联模型的最佳实践是什么:显式使用 Repo.preload 或指定在定义查询时应预加载的关联? 最佳答案 它们是等效的,因此任何方法都可以,真的。如果您想将所有内容都放在
有什么办法可以逆向预加载吗? %Post{ comments: [] } posts = Repo.all(Post) |> Repo.unload(:comments) %Post{ com
使用 Ecto 访问大写字段的最佳方式是什么? 我必须处理一个相当困惑的模式。有些列是大写的。 我设置了以下模型: defmodule SourcesApi.SourceStatus do use
在下面的链接中做了一些研究之后 https://github.com/elixir-lang/ecto/tree/master/examples/simple 我对如何在 elixir 中使用 ect
有没有办法通过选择另一个连接列来预加载记录? # table structure # User 1---* Post 1---* PostTag *---1 Tag # extract definit
考虑以下架构: defmodule EctoBug.Post do use Ecto.Schema import Ecto.Changeset schema "posts" do
这些都不起作用: from m in Model, where: m.name == ^~r(/.*#{query}.*/i)from m in Model, where: m.name =~ ^~r
假设我有这些模式: defmodule Sample.Post do use Ecto.Schema schema "post" do field :title has_man
我有一个针对多个数据库的应用程序,它就像一个监视应用程序的应用程序,它以一种不可能静态控制的方式(在配置文件中)生成报告、调解通知、运行任务和东西,所以我认为它可以启动一个监督多个 Repo 的主管来
我正在尝试编写单个变更集,以更新模型并插入关联。我找不到有关如何使用 put_assoc/4 的示例 order = order |> Proj.Order.changeset(%{sta
我正在寻找所有 User在其 match_history 中没有特定字符串元素的 s field 。我对此进行了猜测: matched_user = User |> where([u], ^devic
我无法成功运行 Ecto 迁移以删除最初创建时提供的唯一索引 :name属性(以便不使用默认索引名称)。但是,我现在无法删除该索引,因为似乎 Ecto 正在尝试查找名称不正确的索引(尽管我已经提供了它
为什么在 Ecto changeset方法您是否将参数设置为默认值:empty原子?例如 def changeset(user, params \\ :empty) do ... 这是否允许您使
注意:我使用的是 MySQL 5.7。 我有两个名为 Post、Comment 的表 schema "posts" do field: id, string field :titl
我是一名优秀的程序员,十分优秀!