首页 > 解决方案 > 用于提供重复条目的字符串的自定义自动递增字段

问题描述

我目前正在开发一个应用程序,该应用程序要求在系统中注册的每个学生在注册时都有一个唯一的注册号,每次注册都会自动递增。2019年注册的第一个学生的注册号格式为“01/19”,第890个学生的注册号格式为“890/19”等。

注册数据是从kobo 数据收集 工具上传的,因此它会在非常短的时间间隔内到达我的端点,因为一次可以完成近 200 次提交。

我意识到在 1000 条记录中,有近 27 个重复的注册号。这就是我实现注册号生成逻辑的方式

def registration_changeset(student, attrs) do
    student |> changeset(attrs) |> Accounts.add_registration_number()
 end

然后 Accounts 上下文具有以下用于添加注册号的代码

def add_registration_number(changeset) do
  struct = changeset.data.__struct__
  registration_number =
  case struct |> last() |> Repo.one() do
    nil -> _create_new_registration_number()
    resource -> _increment_registration(resource.registration_number)
  end

  put_change(changeset, :registration_number, registration_number)
end

在上述情况下,我打赌最后创建的学生将拥有最新的注册号

有没有更好的方法来实现这一点?

标签: elixirphoenix-frameworkecto

解决方案


您在这里需要一些同步代码:)

创建一个专用流程,服务于单一目的:产生数字。GenServer.handle_call/3已经做了你需要的任何事情,进程邮箱是完美的队列,OTP 会为你做一切。

defmodule MyApp.RegNumHelper do
  @moduledoc false

  use GenServer

  def start_link(opts),
    do: GenServer.start_link(__MODULE__, opts, name: name)

  def add_registration_number(changeset),
    do: GenServer.call(__MODULE__, {:reg_num, changeset})


  @impl true
  def init(opts), do: {:ok, opts}

  @impl true
  def handle_call({:reg_num, changeset}, _from, state) do
    # your logic assigning changeset
    {:reply, changeset, state}
  end
end

这种方法还有另一个优点:由于该过程已经是有状态的,因此您实际上不需要每次都查询数据库。只需在进程开始时查询它并将当前数字保存到state.


推荐阅读