gpt4 book ai didi

mysql - ActiveRecord 4 + SQLite3 bool 查询支持中的回归?

转载 作者:行者123 更新时间:2023-11-29 06:41:46 26 4
gpt4 key购买 nike

我正在尝试将我的代码从 ActiveRecord 3 升级到 ActiveRecord 4,我相信我在 ActiveRecord + SQLite3 的 bool 查询支持中遇到了错误/回归。

这是运行 ActiveRecord 4.0.2 的 IRB session 的输出,其中 SQLite3 是数据库后端:

2.0.0p353 :040 > StoreItem.where(item_class: 1, enabled: 1).order(item_order: :desc).count
=> 4
2.0.0p353 :041 > StoreItem.where(item_class: 1, enabled: true).order(item_order: :desc).count
=> 0

作为比较点,当 Mysql 5.5 是数据库后端时,这里是相同的输出:

2.0.0p353 :005 > StoreItem.where(item_class: 1, enabled: 1).order(item_order: :desc).count
=> 4
2.0.0p353 :006 > StoreItem.where(item_class: 1, enabled: true).order(item_order: :desc).count
=> 4

现在,让我们看看使用 AR 3.2.14 运行时会发生什么:

SQLite3:

2.0.0p353 :005 > StoreItem.where(item_class: 1, enabled: 1).order(item_order: :desc).count
=> 0
2.0.0p353 :006 > StoreItem.where(item_class: 1, enabled: true).order(item_order: :desc).count
=> 4

MySQL 5.5:

2.0.0p353 :001 > StoreItem.where(item_class: 1, enabled: 1).order(item_order: :desc).count
=> 4
2.0.0p353 :002 > StoreItem.where(item_class: 1, enabled: true).order(item_order: :desc).count
=> 4

如您所见,当出现 bool 查询时,ActiveRecord 3.2.14 和 4.0.2 在 SQLite3 中做完全相反的事情。

我刚刚检查了实际生成的 SQL,它是相同的。第一个查询如下所示:

SELECT COUNT(*) FROM "store_items" WHERE "store_items"."item_class" = 1 AND "store_items"."enabled" = 1

第二个看起来像这样:

SELECT COUNT(*) FROM "store_items" WHERE "store_items"."item_class" = 1 AND "store_items"."enabled" = 't'

因此,也许 SQLite3 从 1.3.5 到 1.3.8 在处理 bool 列值方面发生了变化?

这是一个已知的错误吗?有人可以评论原因吗?

最佳答案

我调试了 ActiveRecord 3.2.14 和 4.0.2 的核心。这是从头到尾的错误:

SQLite 允许您插入任意字符串/数字作为 bool 列的列值。因此,您可以为 bool 列值插入 1 或“t”。

ActiveRecord 在与 SQLite 交互时将 bool 值映射到字符串类型 't' 或 'f',而不是 1 或 0。该决定背后的原因可能源于 Postgres,但目前是这样。

ActiveRecord在3.2.14第一次创建记录时,at line 365 in persistence.rb ,它创建所有模型字段的映射并插入所有字段,无论它们是否已更改。这是创建方法:

def create
attributes_values = arel_attributes_values(!id.nil?)

new_id = self.class.unscoped.insert attributes_values

self.id ||= new_id if self.class.primary_key

IdentityMap.add(self) if IdentityMap.enabled?
@new_record = false
id
end

这会导致 ActiveRecord 生成如下插入语句(注意 enabled 的存在,我们的 bool 列):

INSERT INTO "store_items" ("created_at", "enabled", "other_columns....") VALUES (?, ?, ?)  [["created_at", 2014-01-11 21:47:24 UTC], ["enabled", true], ["other_colummns", ...]]

在 ActiveRecord 4.0.2 中,文件 dirty.rb, line 78 , 现在调用 persistence.rb (at line 507) 的 create_record 方法.创建记录如下所示:

def create_record(attribute_names = @attributes.keys)
attributes_values = arel_attributes_with_values_for_create(attribute_names)

new_id = self.class.unscoped.insert attributes_values
self.id ||= new_id if self.class.primary_key

@new_record = false
id
end

因为 create_record 现在接受一个仅列出那些已更改的列的参数,所以它生成一个插入语句,该语句不包括其默认值与您正在插入的列相匹配的列。因此,使用与默认值匹配的 bool 值的插入语句将如下所示:

INSERT INTO "store_items" ("created_at", "other_columns....") VALUES (?, ?, ?)  [["created_at", 2014-01-11 21:47:24 UTC], ["other_colummns", ...]]

请注意,缺少 bool 列“已启用”,因为在这种情况下,我们的默认值 true/1 与我们第一次创建记录时插入的值匹配。

因为启用不是由 ActiveRecord 生成的插入语句指定的,SQLite 给它的值是 1,而不是 't' 的值,这是 ActiveRecord 3.1.14 过去给它的值。

最终,要解决此错误,请不要在 bool 列上包含默认值或确保将其更改为非默认值以强制 ActiveRecord 实际将其设置为 't' 或 'f ' 创造值(value)。

因此,改变这个:

class CreateStoreItems < ActiveRecord::Migration
def change
create_table :store_items do |t|
t.boolean :enabled, :null => false, :default => 1
end
end
end

对此

class CreateStoreItems < ActiveRecord::Migration
def change
create_table :store_items do |t|
t.boolean :enabled, :null => false
end
end
end

或者,如果您“旋转” bool 值而不是依赖默认值,您也可以更正错误。

关于mysql - ActiveRecord 4 + SQLite3 bool 查询支持中的回归?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21066345/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com