ruby-on-rails – 将数据库名称添加到表的Rails 3包括默认加载

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – 将数据库名称添加到表的Rails 3包括默认加载前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
资料来源:

> http://emphaticsolutions.com/2009/11/23/has_many_through_across_databases.html
> http://blog.arkency.com/2013/12/rails4-preloading/@H_502_4@

我的项目正在转向拥有多个数据库(目前在同一台服务器上),我希望能够在这些数据库之间加入.为了做到这一点,我需要将数据库名称添加到表前缀,如下所示:@H_502_4@

class FirstBase < ActiveRecord::Base
    def self.table_name_prefix
        "DBNAME.t_"
    end

    establish_connection :firstdb
end

class User < FirstBase
    has_many :user_roles
end

class UserRole < FirstBase
    belongs_to :user
end

添加名称前缀似乎会影响包含在同一查询上的默认行为,即使在同一数据库中也是如此.考虑User.includes(:user_roles).first@H_502_4@

没有表名前缀:@H_502_4@

User Load (67.1ms) SELECT t_users.* FROM t_users LIMIT 1
UserRole Load (84.5ms) SELECT t_user_roles.* FROM t_user_roles WHERE
t_user_roles.user_id IN (1)@H_502_4@

使用表名前缀:@H_502_4@

sql (76.8ms) SELECT DISTINCT DBNAME.t_users.id FROM DBNAME.t_users LEFT OUTER JOIN DBNAME.t_user_roles ON DBNAME.t_user_roles.user_id = DBNAME.t_users.id LIMIT 1@H_502_4@

sql (66.4ms) SELECT DBNAME.t_users.id AS t0_r0,DBNAME.t_users.email AS t0_r1,DBNAME.t_user_roles.id AS t1_r0,DBNAME.t_user_roles.user_id AS t1_r1 FROM DBNAME.t_users LEFT OUTER JOIN DBNAME.t_user_roles ON DBNAME.t_user_roles.user_id = DBNAME.t_users.id WHERE DBNAME.t_users.id IN (1)@H_502_4@

换句话说,调用包含的默认行为已经从预加载更改为热负载.@H_502_4@

有人知道为什么默认行为正在改变吗?必须有一些关于添加数据库名称,使Rails认为我们必须加载,但我不明白为什么.我也很惊讶地看到这一点,因为我想象的是添加数据库名称是不寻常的.我可以通过更改所有包含预加载来强制将其修复到我们的代码库中,但我想了解这里发生了什么.有没有办法改变默认行为?@H_502_4@

解决方法

问题是table_name_prefix引入了一个句点.这混淆了试图确定它是否应该预加载或加载的逻辑.这是一个Rails 3错误,已在Rails 4中解决.如果您需要Rails 3中的特定行为,则需要明确指定预加载或eager_load,就像您在问题中所指出的那样.

ActiveRecord::Relation,exec_queries调用eager_loading?来决定是否应该加载.这调用references_eager_loaded_tables?它使用tables_in_string尝试在SQL查询中查找不是连接表的一部分的表名:@H_502_4@

# ActiveRecord::Relation#references_eager_loaded_tables?
(tables_in_string(to_sql) - joined_tables).any?

tables_in_string方法有缺陷,因为它并不总是正确解析sql.该代码可用于查看SQL查询中表名的内容:@H_502_4@

relation = User.includes(:user_roles)
relation.send(:tables_in_string,relation.to_sql)

使用DBNAME.t_表名前缀,这将给出[“DBNAME”,“t_users”]作为表名,这是错误的.它应该给[“DBNAME.t_users”].@H_502_4@

ActiveRecord query changing when a dot/period is in condition value记录了类似的问题.这导致ActiveRecord::Relation的变化在决定是预加载还是加载负载时,不再使用tables_in_string.@H_502_4@

猜你在找的Ruby相关文章