首页 > 解决方案 > 为什么这段代码总是从数据库中提取?

问题描述

当我导航到各个页面时,总是执行数据库查询,但我希望它只在第一次执行,然后将 firstName 存储在会话 var 中。

 defp get_first_name(conn, %{email: email}) do
    firstName = if sessionFirstName = get_session(conn, :firstName) do
      # found firstName in the session conn variable
      sessionFirstName
    else
      user_record = EVALUsers.get_eval_user_by_email!(email)

      %{firstName: firstName} = user_record
      firstName
    end

    if firstName do
      conn
      |> assign(:firstName, firstName)
      |> put_session(:firstName, firstName)
    else
      conn
      |> assign(:firstName, email)
      |> put_session(:firstName, email)
    end
  end

提前致谢!斯科特

标签: databaseelixirphoenix-frameworkecto

解决方案


请记住,这=是 Elixir 中的匹配运算符,而不是赋值运算符。请注意,您的第一if条语句具有匹配运算符,而不是==条件运算符。

第一次执行您的函数时,sessionFirstName包含一个nil值。该get_session()调用还返回一个nil值,因为:firstName在会话中找不到该键。因此,第一个中的匹配运算符if找到了一个匹配项,这导致条件计算为true。这导致它返回 的值sessionFirstName,即nil,并将其放入firstName变量中。最后一条if语句发现 is 的值firstNamenil假的,因此它评估else并将变量的值存储email在会话中。

下次执行您的函数时,sessionFirstName再次包含一个nil值。该if语句将get_session()调用的返回值(这一次实际上应该返回一个值)与 的值进行比较sessionFirstName,发现它们不匹配。这会导致else子句被执行,并且您的数据库被命中,并且返回的值被放入会话中。此后,由于会话返回一个值但sessionFirstName包含 a nil,因此本段中描述的操作每次都会执行。

我的建议是使用cond结构来测试各种可能性。

defp get_first_name(conn, %{email: email}) do
  firstName =
    cond do
      sessionFirstName = get_session(conn, :firstName) ->
        sessionFirstName
      %{firstName: firstName} = EVALUsers.get_eval_user_by_email!(email) ->
        firstName
      true ->
        email
    end

  conn
  |> assign(:firstName, firstName)
  |> put_session(:firstName, firstName)
end

推荐阅读