【问题标题】:Why datamapper does not update records / detect dirtiness?为什么 datamapper 不更新记录/检测脏污?
【发布时间】:2012-12-17 15:30:29
【问题描述】:

我最近想写一个简单的迁移脚本。我写道:

@entries = Entries.all(:text => /test/)

@entries.each do |entry|
  entry.update(:text => entry.text.gsub!(/test/, "no-test"))
end

即使更新语句返回 true,它也没有保存记录。我错过了什么?

【问题讨论】:

    标签: ruby database migration datamapper ruby-datamapper


    【解决方案1】:

    在 1.x 系列的 datamapper 中,脏跟踪是通过在新旧属性值上调用 #== 来检测脏的。如果一个对象在原地发生变异(例如使用 String bang 方法),则无法检测到更改,因为“原始”状态也发生了变异。

    基本上在内部发生以下情况:

    a = "foo"
    b = a.gsub!("foo", "bar")
    a == b     # => true both a and b refer to the same mutated object
    a.equal?(b) # => true
    

    在您的示例中,您将原始变异属性分配回对象,没有身份更改 => 未检测到更新。

    如果您通过String#gsub 创建一个新对象而不是通过String#gsub! 改变原始属性值,您最终会得到可检测到的更改。

    分配具有不同值的新对象会发生以下情况:

    a = "foo"
    b = a.gsub("foo", "bar")
    a == b      # => false, loaded state does not equal resource state so change is detected
    a.equal?(b) # => false
    

    为了涵盖所有情况,分配一个具有相同值的新对象:

    a = "foo"
    b = "foo"
    a == b      # => true, no dirtyness detected.
    a.equal?(b) # => false
    

    希望这能很好地解释语义差异,以解释所有类似情况。

    顺便说一句,在 datamapper 2.0 中,我们有一个不同的机制,它也可以捕获原地突变。免责声明,我是这个名为dm-session 的组件的作者。

    【讨论】:

    • 啊!使用 Equals 检测更新的增量 - 我疯狂地试图找到正确的“搜索关键字”来了解数据映射器如何计算出要在 Master-Detail 类型的域对象中写入的确切记录集。使用枚举 {add/deleted/updated} 或脏标志似乎不正确。如果您有这方面的任何资源,请分享 - 谢谢!
    • 枚举在内部表示为 Fixnums 的位图。 Fixnums 不能在 ruby​​ 中就地改变,所以这不是问题。假设您正在谈论来自 dm-types gem 的枚举。
    【解决方案2】:

    去掉感叹号。

    entry.update(:text => entry.text.gsub(/test/, "no-test"))

    替换字符串内容时记录不会变脏。你应该重新分配它。

    【讨论】:

    • 谢谢,现在我明白为什么! 代表dangerous ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-19
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多