简体   繁体   English

Rails建模:将HABTM转换为has_many:through

[英]Rails modeling: converting HABTM to has_many :through

I'm doing maintenance work on an existing Rails site and am having some problems stemming from many-to-many associations. 我正在现有的Rails站点上进行维护工作,并且遇到了来自多对多关联的一些问题。 It looks like the site was initially built using has_and_belongs_to_many for a few relationships that have since gotten more complicated in the business logic, so I need to use has_many :through instead to support additional fields in the relationship table. 看起来该站点最初是使用has_and_belongs_to_many为几个关系构建的,这些关系后来在业务逻辑中变得更加复杂,所以我需要使用has_many :through来支持关系表中的其他字段。 However, the join table that was initially used for HABTM doesn't have a primary key, and I've got to add one to support separate relationship modeling using has_many :through . 但是,最初用于HABTM的连接表没有主键,我必须添加一个以支持使用has_many :through单独的关系建模。

What's the best way to add a primary key to an existing table with lots of data? 将主键添加到包含大量数据的现有表的最佳方法是什么? Is there another way to do what I'm trying to? 还有另一种方法可以做我正在尝试的事情吗?

Incidentally, the system is running on Oracle. 顺便提一下,系统在Oracle上运行。

Thanks! 谢谢!

Justin 贾斯汀

UPDATE 11/9/09 3:58pm: I'm not an Oracle expert and have been getting lost in the wilds of Oracle's versions of not null, auto-increment, and so forth. 更新11/9/09 3:58 pm:我不是Oracle专家,并且已经迷失在Oracle版本的非null,自动增量等等。 Initially I tried doing what Mike and Corey recommended by adding a new field as a primary key, but Oracle wouldn't let me add a non-null field to a non-empty table (ORA-01758). 最初我尝试通过添加新字段作为主键来执行Mike和Corey所建议的操作,但Oracle不允许我将非空字段添加到非空表(ORA-01758)。 I then exported the data as SQL, dropped the rows, added the PK and set it to be non-null, then tried to import the data, but I kept getting errors to the tune of "cannot insert NULL into id..." (ORA-01400). 然后我将数据导出为SQL,删除行,添加PK并将其设置为非null,然后尝试导入数据,但我不断收到“无法将NULL插入id ...”的错误。 (ORA-01400)。

Finally, I tried using a migration as Corey suggests in his comment, but rake hit the same errors that Oracle was throwing when I altered the database manually ("cannot add non-null field to non-empty table"). 最后,我尝试使用迁移,正如Corey在他的评论中所建议的那样,但是当我手动更改数据库时,rake遇到了Oracle抛出的相同错误(“无法将非空字段添加到非空表”)。 I cleared the table, ran the migration (which worked), and then attempted to re-import the data, but I got the same errors last time I'd tried to import ("cannot insert NULL into id..."). 我清理了表,运行了迁移(有效),然后尝试重新导入数据,但是上次我尝试导入时遇到了相同的错误(“无法将NULL插入id ...”)。 How can I save my data and add the primary keys I need? 如何保存数据并添加我需要的主键? I know that the possibility of writing a rake task was suggested, but I'm unsure as to how to proceed on that front. 我知道有可能写一个rake任务,但我不确定如何继续前进。 Any ideas? 有任何想法吗?

I use SQL Developer when administrating an oracle database. 我在管理oracle数据库时使用SQL Developer Just create the column and add a constraint to the database for example: 只需创建列并向数据库添加约束,例如:

sql> alter table Employee add constraint Employee_pk primary key(Employee_ID);

Maybe see here for some more detail. 也许在这里看一些更详细的信息。

Edit: 编辑:

Now that I rethink this you should be able to do it in a migration 现在我重新考虑这个,你应该能够在迁移中做到这一点

add_column :table, :id, :primary_key

You then need to seed some data inside the migration. 然后,您需要在迁移中植入一些数据。 Just ruby code that iterates through and adds your index. 只是ruby代码迭代并添加您的索引。 See seed_fu and db-populate for help. 请参阅seed_fudb-populate以获取帮助。 Rails 3 will let you seed data with rake db:seed. Rails 3将允许您使用rake db:seed播种数据。

You need to create the new column, fill it with the PK values and then create a PK on the new column, eg: 您需要创建新列,使用PK值填充它,然后在新列上创建PK,例如:

SQL> create table no_pk_tab (c1 varchar2(10), c2 varchar2(10))
Table created.
SQL> insert into no_pk_tab values ('one', 'one')
1 row created.
SQL> insert into no_pk_tab values ('two', 'two')
1 row created.

SQL> alter table no_pk_tab add (id integer)
Table altered.

SQL> create sequence no_pk_seq
start with 1
increment by 1
Sequence created.

SQL> update no_pk_tab set id = no_pk_seq.nextval
2 rows updated.
SQL> select * from no_pk

C1         C2             PK_COL
---------- ---------- ----------
one        one                 1
two        two                 2

2 rows selected.

SQL> alter table no_pk add primary key (pk_col) using index
Table altered.

Depending on how many rows are in your table it may take a while to populate the sequence values, but it will work. 根据表中的行数,可能需要一段时间来填充序列值,但它会起作用。

Use alter table to add the pk column. 使用alter table添加pk列。

Write a script to set the new pk column values incrementally (some sort of loop). 编写脚本以逐步设置新的pk列值(某种循环)。

Once the script is done use alter table again to set the column to primary_key and auto-increment, setting the increment start value to table_size + 1. 完成脚本后,再次使用alter table将列设置为primary_key并自动递增,将increment start值设置为table_size + 1。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM