当前位置:首页 > ActiveRecord(Ruby)
order.name = \ order.save
不管怎样,在下面的例子里,Active Record对象只包含id,name,paytype,当对象被保存的时候仅仅只有这些字段被更新,注意如果你想要把对象保存到数据库,那么在使用find_by_sql方法时,一定要包含id字段。
orders = Order.find_by_sql(\ first = orders[0] first.name = \ first.save
另外,Active Record还提供了update_attribute()方法,该方法可以将Model对象的某个属性保存到数据库。 order = Order.find(123)
order.update_attribute(:name, \ order = Order.find(321)
order.update_attributes(:name => \ :email => \
我们可以把读取和更新结合在一起,使用update()方法或update_all(),update()方法使用一个id和一组属性,如果在数据库中对应的记录,就更新指定的属性,然后返回model对象。
order = Order.update(12, :name => \
也可以传递一组id或者属性和值的hash给update()方法,这样会更新所有匹配的记录,并且返回一组model对象。
最后,update_all()方法允许你指定给update语句指定Where条件,下面的例子给所有标题中含有java的商品涨价10%:
result = Product.update_all(\
这里的返回值依赖于具体的数据库适配器,很多数据库都返回被更新的记录数目。 下面我们看看save()和save!()这两个方法。
简单的save()方法在Model对象存在并且可以的保存的情况下返回true: if order.save # all OK else
# validation failed end
这样会导致你在所有调用save方法的地方都要加上检查,但是Active Record假定save方法是在Controler的Action的上下文中的,并且视图里的代码不进行这些检查。(这部分书上看不明白,不能确定)。
不管怎样,如果你需要在上下文环境中保存Model对象,并且想确定是否所有的错误都被处理了,你可以使用save!()方法,如果Model对象不能保存,那么这个方法会抛出一个RecordInvailid异常: begin
order.save!
rescue RecordInvalid => error # validation failed end
在学习Rails中的并发处理的处理前,我们先简单了解下并发处理的概念。 在有多个处理同时访问同一个数据库的应用程序中,可能会出现这样的情况,因为一个处理更新了数据库中的行,而使得另一个处理中持有的数据变得陈旧了。例如,A和B先后从数据库中提取了相同的数据,并都做了修改,这时B先将自己的修改更新会数据库,稍后,A将自己的修改更新回数据库,这时将会覆盖B所作的修改,当B再次提取数据库后,看到的是A修改的结果,而不是自己的。
一个解决办法就是将更新的表或者行进行锁定,防止其他程序进行更新或者访问,锁定可以完全避免并发的问题,也常称作悲观锁,但是在Web项目中,这个做法是行不通的,因为在同一个时间点上,可能会有很多个用户需要访问数据。
乐观锁并没有将数据锁定的外在表现,作为替代,在将修改写回到数据库之前,进行检查来确定一条记录是否已经被修改了。在Rails里的实现方法是,每和行都包含有一个版本号(version number),不管什么时候行被更新了,版本号就会被增加,当你在你的程序中进行一个更新操作时,Active Record检查行和Model的版本号,如果不匹配,将会放弃修改并抛出一个异常。
对于任何一个包含有integer型的字段lock_version的表,乐观锁都会默认的被启用,你可以把新行的这个字段初始为0,但是,如果你忘记了,Active Record也会替你完成。 我们来看看怎样实现乐观锁,我们创建一个名为counters的表: create table counters (
id int not null auto_increment, count int default 0,
lock_version int default 0, primary key (id) );
然后我给这个表创建一个行,将这个行读入到不同的Model中,并且在其中尝试更新, class Counter < ActiveRecord::Base end
Counter.delete_all
Counter.create(:count => 0) count1 = Counter.find(:first) count2 = Counter.find(:first) count1.count += 3 count1.save
count2.count += 4 count2.save
当我们运行上面的代码,会得到一个异常,Rails会放弃count2所作的修改,因为其中包含的已经是脏数据了。
如果使用了乐观锁,就需要在程序中处理这些异常,也可以禁用乐观锁: ActiveRecord::Base.lock_optimistically = false
关于乐观锁,可以参考Martin Flower所著的《企业应用解决方案及模式》一种中关于并发处理和工作单元(Work Unit)模式的内容,相信对Rails的并发处理机制会有更深的了解。
Active Record提供了两种方式进行删除操作。首先,有两个类级别的方法,delete和delete_all,这两个操作处在数据库层面上,delete()方法接收一个或一组和数据库对应的id,delete_all()方法删除所有符合指定条件的记录,如果没有指定条件,就会删除所有的
记录。方法的返回值和具体的数据库适配器相关,例如oracle返回被影响的行数。如果没有记录被删除,也不会抛出异常。 Order.delete(123)
User.delete([2,3,4,5])
Product.delete_all([\
另外,destory方法删除和数据库中行相对应的Model对象,这样会冻结这些对象,并且不能修改对象的值。
order = Order.find_by_name(\order.destroy
有两个类级别的destory方法,destory()方法接收一个或一组id,destory_all()方法接收删除条件。这两个方法都从数据库中读出对应的记录到Model对象,并且对这个对象调用实例级别的destory()方法,而且不返回有意义的信息。 Order.destroy_all([\
为什么我们同时需要delete和destory方法呢?delete方法绕过了一些Active Record的回调(callback)和验证函数,而使用destory则不会,通常我们使用destory方法来确保我们的数据库是一致的,并且不会破坏Model中所包含的业务逻辑。 很多程序使用的数据库都包含有多个表,而且通常一些表之间还有关联关系,订单常含有多个条目,而一个条目又关联到一种商品,一个商品可能又属于多个商品分类,一个商品分类里又包含有多个不同的商品。
在数据库中,这些关联表现为使用主键值把表关联起来,也就是外键,但是这属于底层的范畴,我们需要处理Model对象间的关联,而不是数据库中的列和键。如果一个订单含有多个条目,我们需要有办法来维持,处理它们的关系,如果一个条目引用到一种商品,我们或许想这样做:
price = line_item.product.price 而不愿像下面这样麻烦:
product_id = line_item.product_id product = Product.find(product_id) price = product.price
Active Record可以帮助我们,作为ORM的一部分,Active Record将低级别的数据库中的外键转换成高级别的对象间的映射。处理了三种基本情况: A表中的一条记录和B表的零条或一条记录相关联。 A表中的一条记录和B表的任意多条记录相关联。 A表中的任意多条记录和B表的任意多条记录相关联。
下面我们来看看怎样创建外键(Foreign Key),我们使用下面的DDL来创建表,它们之间指定了关联:
create table products (
id int not null auto_increment, title varchar(100) not null, /* . . . */
primary key (id) );
create table orders (
id int not null auto_increment, name varchar(100) not null,
/* ... */
primary key (id) );
create table line_items (
id int not null auto_increment, product_id int not null, order_id int not null,
quantity int not null default 0, unit_price float(10,2) not null,
constraint fk_items_product foreign key (product_id) references products(id), constraint fk_items_order foreign key (order_id) references orders(id), primary key (id) );
在上面的DDL中,订单和条目关联,条目又关联到具体的商品。注意这里的命名约定,外键的名字product_id,product是products表的单数形式,然后再加上表的主键名字_id构成外键名。
上面的DDL中,订单和条目是一对多的关系,还有一种是多对多关系,例如,一种商品属于多个商品分类,一个商品分类又含有多种商品。对这种情况,通常我们使用第三个表,叫做结合表,这个表只包含两个要关联的表的id: create table products (
id int not null auto_increment, title varchar(100) not null, /* . . . */
primary key (id) );
create table categories (
id int not null auto_increment, name varchar(100) not null, /* ... */
primary key (id) );
create table categories_products ( product_id int not null, category_id int not null,
constraint fk_cp_product foreign key (product_id) references products(id), constraint fk_cp_category foreign key (category_id) references categories(id) );
注意结合表的命名,在这里Rails的约定为两个表名,中间用下划线分开,表名按照字母排序,Rails会自动找到categories_products表将categories表和products链接起来,如果你没有按照约定,那么就要自己声明,以便Rails能够找到它。
Rails支持三种表间关联关系,一对一,一对多,多对多,你需要在Model中加入声明来标识这些关联:has_one,has_many,belongs_to,has_and_belongs_to_many。
一对一关联关系可能存在于象订单和发票这样的关系,一个订单只能有一个发票,在Rails中,我们这样指明:
共分享92篇相关文档