在Ruby DataMapper中保存实例时的奇怪行为

在Ruby DataMapper中保存实例时的奇怪行为,ruby,datamapper,Ruby,Datamapper,刚刚开始研究DataMapper for Ruby ORM,我遇到了一个让我困惑不已的问题 在DataMapper中保存实例时(通过DataMapper::Resource.save)的默认行为是,据我所知,以静默方式失败,从save方法返回false,并在errors集合中收集任何错误。到目前为止,一切顺利,正如预期的那样。我看到的问题是自然主键,设置重复主键将引发异常,而不是从save方法中静默返回false,公然忽略当前设置save\u失败时升高。考虑下面的片段; require 'da

刚刚开始研究DataMapper for Ruby ORM,我遇到了一个让我困惑不已的问题

在DataMapper中保存实例时(通过DataMapper::Resource.save)的默认行为是,据我所知,以静默方式失败,从save方法返回false,并在errors集合中收集任何错误。到目前为止,一切顺利,正如预期的那样。我看到的问题是自然主键,设置重复主键将引发异常,而不是从save方法中静默返回false,公然忽略当前设置save\u失败时升高。考虑下面的片段;
 require 'data_mapper'

class Thing
  include DataMapper::Resource
  property :name , String, :key=>  true
  property :description, String, length: 2..5
end

DataMapper.setup :default, "sqlite:memory"
DataMapper.finalize
DataMapper.auto_migrate!

#Create a thing and have it properly silently fail saving
t1=Thing.new(:name=>"n1",:description=>"verylongdescription" )

t1.save #ok
puts("t1 is saved:"+t1.saved?.to_s)
t1.errors.each do |e|
  puts e
end

#Create two things with the same key, and fail miserably in silently failing the second     save...
t1=Thing.new(:name=>"n1",:description=>"ok" )
t2=Thing.new(:name=>"n1",:description=>"ok" )

t1.save #ok
t2.save #not ok, raises Exception event though it shouldn't?

puts("t2 is saved:"+t1.saved?.to_s)
t2.errors.each do |e|
  puts e
end
在实例上的第一次保存未通过:description属性的验证规则,其行为符合预期。但是,具有重复键的实例的第三次保存不会,因为它会引发一个execption,而不是仅仅返回false

为什么会这样?很明显,这是可以解决的,但感觉不是很清楚。是否静默行为仅适用于DataMapper层中的验证错误,并且来自底层数据存储的任何硬错误将作为异常传播给调用方


谢谢

另一位用户在评论中指出,之所以会出现这种情况,是因为将
raise\u on\u save\u failure
设置为
false
并不意味着不会发生异常。发生验证错误时,它将始终返回
false
(无例外)


正如您所注意到的,数据库错误将以异常的形式爆发。这种错误可能是由许多因素造成的(连接失败,没有磁盘空间),包括像复制密钥这样的普通因素。DataMapper无法知道您试图保存的对象是否拥有一个重复的密钥,因此它只是验证它并发送到数据库,而实际发生错误的地方。

验证捕获最终用户错误,复制到数据库的密钥是程序员错误。如果您在
保存
序列中被零除或未正确处理
nil
,您将得到一个基于相同原因的异常。是的,这是一个有意义的区别,我现在更了解了DataMapper中验证和静默/非静默行为的目的。我猜在上面的例子中,如果你添加了一个唯一的验证;不幸的是,唯一性验证是不够的,因为它受竞争条件的影响,所以您也需要数据库中的唯一约束,但是当竞争条件发生时,您会得到一个异常。