自定义自动递增字段,用于为字符串提供重复条目

时间:2019-01-03 16:06:40

标签: elixir phoenix-framework ecto

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

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

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

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

然后,“帐户”上下文具有以下用于添加注册号的代码

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

在上述情况下,我押注最后一个创建的学生具有最新的注册号

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

2 个答案:

答案 0 :(得分:1)

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

创建一个专门用于以下目的的过程:产生数字。 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中即可。

答案 1 :(得分:0)

最简单的解决方案是,您可以将自动递增的ID设为注册号的第一部分,然后将两位数字的年本身存储为字段。然后,在模型中,您将简单地拥有一个由“ get_registration_number”组成的方法。这样可以解决重复问题。

不利的一面是,您将拥有890/19作为2019年的最后一个学生,然后有891/20作为2020年的第一个学生,而不是01/20。但是您的示例似乎也无法处理这种情况,并且隐含(但不清楚)这是必要条件。

如果是这样,您可以创建一个像以前一样自动递增的列(例如id_num),而不是让ID作为第一部分,然后在年份更改时将该列的下一个值重置为1。如果您想变得偏执,可以说'id_num'列和'two_digit_year'列一起构成一个唯一键。

TL; DR:最简单的方法是让数据库处理它。