rails 主键非 id 查询的奇怪 ORM 行为
Odd ORM behavior for rails query with non id for primary key
给定一个由遗留 table 支持的模型,其中主键是 unique_id
而不是 id
当我使用 id
查询模型时(例如 CustomerLocations.where(id: 123)
) 查询找到了正确的记录,但显示 id
列的错误值。此外,如果我引用该记录的 id
,我将获得主键(即 unique_id
)而不是 id
.
请注意,id 列是 4457777
,PK 是 53710
irb(main):001:0> customer = CustomerLocations.where(id: 445777).first
CustomerLocations Load (0.3ms) SELECT `customer_locations`.* FROM `customer_locations` WHERE `customer_locations`.`id` = 445777
=> #<CustomerLocations id: 53710, unique_id: 53710, name: "Joe Smith", ... >
irb(main):002:0> customer.first.id
=> 53710 # this is the unique id, should have returned 445777
如果我运行同样SQL查询,返回的id值是正确的445777
,非pk。
mysql> SELECT id, unique_id FROM customer_locations WHERE id = 445777;
+--------+-----------+
| id | unique_id |
+--------+-----------+
| 445777 | 53710 |
+--------+-----------+
1 row in set (0.00 sec)
这是模型:
class LegacyBase < ActiveRecord::Base
self.abstract_class = true
establish_connection "ourlegacyprefix_#{Rails.env}".to_sym
#...
end
class CustomerLocations < LegacyBase
self.primary_key = :unique_id
self.table_name = "customer_locations"
belongs_to :customer, foreign_key: 'id'
#...
end
class LegacyCustomer < GnpcbBase
self.table_name = "legacy_customers"
has_many :customer_locations,
foreign_key: 'id',
dependent: :destroy
belongs_to :customer_location
#...
end
class Customer < ActiveRecord::Base
belongs_to :legacy_customer
#...
end
这是我的一些 gemspec
ruby '2.3.1'
gem 'rails', '5.0.0'
gem 'mysql2', '0.4.4'
这是客户的架构,customer_locations
create_table "customer_locations", primary_key: "unique_id", force: :cascade do |t|
t.integer "id", limit: 4, default: 0, null: false
t.string "location_id", limit: 10, default: "", null: false
t.string "name", limit: 60
t.text "address", limit: 65535
t.string "city", limit: 50
t.string "state", limit: 50
t.string "zip", limit: 20
t.string "country", limit: 2, default: "US", null: false
t.string "phone", limit: 50
t.string "email", limit: 100
t.string "location_type", limit: 20
t.date "last_modified"
t.string "checksum", limit: 8
end
add_index "customer_locations", ["id"], name: "id", using: :btree
add_index "customer_locations", ["location_id"], name: "location_id_unique", unique: true, using: :btree
create_table "customers", force: :cascade do |t|
t.string "name", limit: 255, default: "", null: false
t.string "last_name", limit: 50, default: "", null: false
t.string "first_name", limit: 30, default: "", null: false
t.string "customer_category", limit: 20, default: "", null: false
t.string "customer_type", limit: 20, default: "", null: false
t.string "customer_class", limit: 20, default: "", null: false
t.date "last_modified"
end
这是我的模型配置错误还是 Rails 错误?
编辑
注意:如果我在 customer_locations
上将主键设置为 :id
那么它可以工作,但这当然与 table 结构的 pk 冲突。
情况相当混乱...
我会尝试重新映射 id 列:
class CustomerLocations < LegacyBase
...
alias_attribute :secondary_id, :id
end
因此您可以通过 secondary_id
访问它
因为记住 id
是一种方法,而不是实际的列。如果您调用方法 id
,它将 return primary key 值。如果可能的话,我认为你需要先修复你的设置。或者,现在您可以重写模型内部的 id
方法,例如:
def id
_read_attribute(:id)
end
给定一个由遗留 table 支持的模型,其中主键是 unique_id
而不是 id
当我使用 id
查询模型时(例如 CustomerLocations.where(id: 123)
) 查询找到了正确的记录,但显示 id
列的错误值。此外,如果我引用该记录的 id
,我将获得主键(即 unique_id
)而不是 id
.
4457777
,PK 是 53710
irb(main):001:0> customer = CustomerLocations.where(id: 445777).first
CustomerLocations Load (0.3ms) SELECT `customer_locations`.* FROM `customer_locations` WHERE `customer_locations`.`id` = 445777
=> #<CustomerLocations id: 53710, unique_id: 53710, name: "Joe Smith", ... >
irb(main):002:0> customer.first.id
=> 53710 # this is the unique id, should have returned 445777
如果我运行同样SQL查询,返回的id值是正确的445777
,非pk。
mysql> SELECT id, unique_id FROM customer_locations WHERE id = 445777;
+--------+-----------+
| id | unique_id |
+--------+-----------+
| 445777 | 53710 |
+--------+-----------+
1 row in set (0.00 sec)
这是模型:
class LegacyBase < ActiveRecord::Base
self.abstract_class = true
establish_connection "ourlegacyprefix_#{Rails.env}".to_sym
#...
end
class CustomerLocations < LegacyBase
self.primary_key = :unique_id
self.table_name = "customer_locations"
belongs_to :customer, foreign_key: 'id'
#...
end
class LegacyCustomer < GnpcbBase
self.table_name = "legacy_customers"
has_many :customer_locations,
foreign_key: 'id',
dependent: :destroy
belongs_to :customer_location
#...
end
class Customer < ActiveRecord::Base
belongs_to :legacy_customer
#...
end
这是我的一些 gemspec
ruby '2.3.1'
gem 'rails', '5.0.0'
gem 'mysql2', '0.4.4'
这是客户的架构,customer_locations
create_table "customer_locations", primary_key: "unique_id", force: :cascade do |t|
t.integer "id", limit: 4, default: 0, null: false
t.string "location_id", limit: 10, default: "", null: false
t.string "name", limit: 60
t.text "address", limit: 65535
t.string "city", limit: 50
t.string "state", limit: 50
t.string "zip", limit: 20
t.string "country", limit: 2, default: "US", null: false
t.string "phone", limit: 50
t.string "email", limit: 100
t.string "location_type", limit: 20
t.date "last_modified"
t.string "checksum", limit: 8
end
add_index "customer_locations", ["id"], name: "id", using: :btree
add_index "customer_locations", ["location_id"], name: "location_id_unique", unique: true, using: :btree
create_table "customers", force: :cascade do |t|
t.string "name", limit: 255, default: "", null: false
t.string "last_name", limit: 50, default: "", null: false
t.string "first_name", limit: 30, default: "", null: false
t.string "customer_category", limit: 20, default: "", null: false
t.string "customer_type", limit: 20, default: "", null: false
t.string "customer_class", limit: 20, default: "", null: false
t.date "last_modified"
end
这是我的模型配置错误还是 Rails 错误?
编辑
注意:如果我在 customer_locations
上将主键设置为 :id
那么它可以工作,但这当然与 table 结构的 pk 冲突。
情况相当混乱... 我会尝试重新映射 id 列:
class CustomerLocations < LegacyBase
...
alias_attribute :secondary_id, :id
end
因此您可以通过 secondary_id
因为记住 id
是一种方法,而不是实际的列。如果您调用方法 id
,它将 return primary key 值。如果可能的话,我认为你需要先修复你的设置。或者,现在您可以重写模型内部的 id
方法,例如:
def id
_read_attribute(:id)
end