You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Elixir Ecto中create与update场景下changeset坐标转换异常如何解决

问题根因

报错的核心原因是get_change/3仅读取changeset本次提交的变更字段值,未发生变更的字段会返回nil,更新场景下如果没有同时传入经纬度,构造%Geo.Point{}时就会因为nil值触发参数错误。

解决方案

修改cast_coordinates/1函数,优先判断经纬度是否存在变更,仅在有变更时重新计算坐标,取值时优先取本次变更值,无变更则读取已存储的原值:

def cast_coordinates(changeset) do
  # 经纬度无变更时直接返回,不修改坐标字段
  unless Map.has_key?(changeset.changes, :latitude) or Map.has_key?(changeset.changes, :longitude) do
    changeset
  else
    # get_field 优先取本次变更值,无变更自动读取已存储的原值
    lat = get_field(changeset, :latitude)
    lng = get_field(changeset, :longitude)

    # 可选的非空校验,避免无效数据写入
    if is_nil(lat) or is_nil(lng) do
      add_error(changeset, :coordinates, "纬度和经度不能为空")
    else
      geo = %Geo.Point{coordinates: {lng, lat}, srid: 4326}
      put_change(changeset, :coordinates, geo)
    end
  end
end

修改说明

  • 新增变更判断逻辑,位置信息无变更时不会修改coordinates字段,避免不必要的写入和空值风险
  • 用get_field/3替代get_change/3,解决仅更新单个经纬度字段时另一个值为空的问题
  • 可选的非空校验可以拦截创建/更新时经纬度不全的无效请求,符合业务合理性要求

场景验证

你提到的4个异常场景均可被覆盖:

  • 仅更新latitude:longitude自动读取原有存储值,正常生成坐标
  • 仅更新longitude:latitude自动读取原有存储值,正常生成坐标
  • 不更新位置信息:直接跳过坐标转换逻辑,无报错无多余变更
  • 原坐标读取需求通过get_field自动实现,仅在位置变更时才会更新coordinates字段,不会触发无变更判定问题

内容的提问来源于stack exchange,提问作者sooon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 09:51:03