使用DataMapper,我注意到除非我修改整个Object
,否则属性不会更新 - 更新对象的字段然后保存不会保持更改。
我正在更新value
类的UnitValue
属性,我将其存储为Object
类中的ProductQuantity
属性。
require 'data_mapper'
class ProductQuantity
include DataMapper::Resource
property :id, Serial
property :quantity, Object, :required => true
end
# RSpec:
# Create a UnitValue with value 300, save as the Object property of this ProductQuantity
prod_quantity1 = ProductQuantity.create(:quantity => UnitValue.new(300, 'kg'))
expect(prod_quantity1.quantity.value).to eql(300) # true
# Replace the entire UnitValue object
prod_quantity1.quantity = UnitValue.new(400, 'kg')
expect(prod_quantity1.quantity.value).to eql(400)
prod_quantity1.save
# Check save worked when modifying the entire object
expect(ProductQuantity.get(prod_quantity1.id).quantity.value).to eql(400) # true
# Modify only a single field
prod_quantity1.quantity.value = 500
prod_quantity1.save
# Check save worked when modifying a single object - this FAILS
expect(ProductQuantity.get(prod_quantity1.id).quantity.value).to eql(500) # false
答案 0 :(得分:0)
在查看文档并找到outdated thread之后,我相信我找到了解决方案。您可以通过更改DataMapper::Resource
实例的persistence_state将属性标记为脏。
DirtyState = DataMapper::Resource::PersistenceState::Dirty
quantity_property = ProductQuantity.properties[:quantity]
old_quantity = prod_quantity1.quantity
prod_quantity1.quantity.value = 500
dirty_state = DataMapper::Resource::PersistenceState::Dirty.new(prod_quantity1)
dirty_state.original_attributes[quantity_property] = old_quantity
prod_quantity1.persistence_state = dirty_state
expect(prod_quantity1.persistence_state.is_a? DirtyState).to eql(true)
expect(prod_quantity1.dirty?).to eql(true)
prod_quantity1.save
expect(prod_quantity1.dirty?).to eql(false)
基本上我们创建一个DataMapper::Resource::PersistenceState::Dirty
对象,然后使用我的ProductQuantity的“quantity”属性作为键,我们将值设置为original_attributes
中的旧对象。对于prod_quantity1.dirty?
,任何非空地图都将返回true。
我已经把它变成了下面的模块。只需使用一些属性名称调用<resource_instance>.make_dirty(*attributes)
。
require 'data_mapper'
module DataMapper
module Resource
# Make the give attributes dirty
def make_dirty(*attributes)
if attributes.empty?
return
end
unless self.clean?
self.save
end
dirty_state = DataMapper::Resource::PersistenceState::Dirty.new(self)
attributes.each do |attribute|
property = self.class.properties[attribute]
# Any value will do here and return true for self.dirty?, but it expects the old version of this attribute.
dirty_state.original_attributes[property] = nil
self.persistence_state = dirty_state
end
end
end
end
我在下面测试了它:
describe DataMapper::Resource do
before(:all) do
DataMapper.auto_migrate!
@prod1 = Product.create(:name => 'Snickers')
end
after(:all) do
DataMapper.auto_migrate!
end
it 'should fail when an attribute is not dirty' do
prod_quantity1 = ProductQuantity.create(:product => @prod1, :quantity => UnitValue.new(300, 'kg'))
prod_quantity1.quantity.value = 400
expect(prod_quantity1.dirty?).to eql(false)
prod_quantity1.save
prod_quantity1 = ProductQuantity.get(prod_quantity1.id)
expect(prod_quantity1.quantity.value).to eql(300)
end
it 'should mark an attribute as dirty' do
prod_quantity1 = ProductQuantity.create(:product => @prod1, :quantity => UnitValue.new(300, 'kg'))
prod_quantity1.quantity.value = 400
expect(prod_quantity1.dirty?).to eql(false)
prod_quantity1.make_dirty(:quantity)
expect(prod_quantity1.dirty?).to eql(true)
prod_quantity1.save
expect(prod_quantity1.quantity.value).to eql(400)
expect(prod_quantity1.dirty?).to eql(false)
end
end