[转载]Rails 数据库操作
原文地址:Rails 数据库操作作者:浮云
http://blog.sina.com.cn/s/blog_5575d1da0100xulv.html
数据库元被影射成对象
(object-relational mapping (ORM)层)
Ruby代码
table<=>class
row<=>object
column<=>object attribute
class和table的命名对应关系实例:
Ruby代码
Order<=>orders
TaxAgency<=>tax_agencies
Person<=>people
Ruby代码
#复数形式关闭方法config/environment.rb:
ActiveRecord::Base.pluralize_table_names = false
#自定义表格名称方法:
class Sheep < ActiveRecord::Base
set_table_name "sheep"
end
Ruyb数据类型和SQL数据类型对应关系表:
Ruby代码
int,integer<=>Fixnum
float,double,decimal,numeric<=>Float
interval,date<=>Date
datetime,time<=>Time
char,varchar,string,clob,blob,text<=>String
boolean<=>see text...
访问属性(数据库列):
Ruby代码
account[:balance] #=> 返回当前值
account[:balance] = 0.0 #=> 指定数值
Ruby代码
#修正数据库列的取值范围的方法:
class Account < ActiveRecord::Base
def balance=(value)
raise BalanceTooLow if value < MINIMUM_LEVEL
self[:balance] = value
end
end
访问属性(数据库列)更方便的方法:
account.balance #=> 返回当前值
account.balance = 0.0 #=> 指定数值
以上方式得到的数据库数据将是ruby按自身的数据类型格式化好的,如果要得到原始数据,可用以下形式代码:
account.balance_before_type_cast #=> "123.4", 字符串
account.release_date_before_type_cast #=> "20050301"
是非属性
在ruby中只有false或nil才被判断为false
通常用以下代码判断:
Ruby代码
user = Users.find_by_name("Dave")
if user.superuser?
grant_privileges
end
superuser?将以下结果判断为false:
1.数字0
2.字符"0", "f", "false", 或""(空字符)
3.nil
4.常量false
自定义判断原则的方法:
Ruby代码
class User < ActiveRecord::Base
def superuser?
self.superuser == 'J'
end
# . . .
end
数据库主键(Primary Keys)
Ruby on Rails默认以id为主键
自定义主键的方法:
class BadBook < ActiveRecord::Base
set_primary_key "isbn"
end
数据创建,读取,更新和删除(CRUD:Create, Read, Update, Delete)
创建新数据
实例:
Ruby代码
an_order = Order.new
an_order.name ="Dave Thomas"
an_order.email = "[email protected]"
an_order.address = "123 Main St"
an_order.pay_type = "check"
an_order.save #在save()之前所有数据只存在内存中
用以下方式可以减少产生一个an_order变量:
Ruby代码
Order.new do |o|
o.name = "Dave Thomas"
# . . .
o.save
end
当数据来自HTML表单时,可以考虑用以下方式:
Ruby代码
an_order = Order.new(
:name =>"Dave Thomas",
:email =>"[email protected]",
:address => "123 Main St",
:pay_type =>"check")
an_order.save
使用create()代换new()可直接保存到数据库,省去an_order.save:
Ruby代码
an_order = Order.create(
:name => "Dave Thomas",
:email =>"[email protected]",
:address =>"123 Main St",
:pay_type => "check")
可以使用hash同时保存多组数据:
Ruby代码
orders = Order.create(
[ { :name =>"Dave Thomas",
:email => "[email protected]",
:address =>"123 Main St",
:pay_type =>"check"
},
{ :name =>"Andy Hunt",
:email =>"[email protected]",
:address =>"456 Gentle Drive",
:pay_type => "po"
} ] )
new()或create()也可以直接接参数:
order = Order.create(params)
读取数据
Ruby代码
an_order = Order.find(27) # 直接找出id = 27的数据
# 从一个表单读取product id列表,然后计算这些商品的总价:
product_list = params[:product_ids]
total = 0.0
Product.find(product_list).each {|prd| total += prd.total}
Ruby代码
带条件的读取:
pos = Order.find(:all,
:conditions => "name = 'dave' and pay_type = 'po'")
不安全的表单参数传递读取数据库:
Ruby代码
name = params[:name]
# 此方法有被SQL注入方式入侵的风险!!!
pos = Order.find(:all,
:conditions =>"name = '#{name}' and pay_type = 'po'")
#注意上面单双引号的使用及变量的传递方法
更安全的方法:
Ruby代码
name = params[:name]
pos = Order.find(:all,
:conditions => ["name = ? and pay_type = 'po'", name])
你也可以这样:
Ruby代码
name = params[:name]
pay_type = params[:pay_type]
pos = Order.find(:all,
:conditions => ["name = :name and pay_type = :pay_type",
{:pay_type => pay_type, :name => name}])
终极简化版:
Ruby代码
pos = Order.find(:all,
:conditions => ["name = :name and pay_type = :pay_type", params])
排序和查找第3(?)至13(?)列的方法:
Ruby代码
orders = Order.find(:all,
:conditions =>"name = 'Dave'",
:order =>"pay_type, shipped_at DESC",
:limit => 10
:offset => 2)
联合数据表的查找方法(一般用不上):
Ruby代码
LineItem.find(:all,
:conditions => "pr.title = 'Programming Ruby'",
:joins =>"as li inner join products as pr on li.product_id = pr.id")
查找有序一列的方法:
Ruby代码
order = Order.find( :first,
:conditions =>"name = 'Dave Thomas'",
:order => "id DESC")
直接使用sql语句的查询方法:
Ruby代码
items = LineItem.find_by_sql("select *, quantity*unit_price as total_price,products.title as title from line_items, products where line_items.product_id = products.id ")
li = items[0]
puts "#{li.title}: #{li.quantity}x#{li.unit_price} => #{li.total_price}"
#你可以使用"as".
在这里你也可以传递参数:
Ruby代码
Order.find_by_sql(["select * from orders where amount > ?",
params[:amount]])
计算行数
Ruby代码
c1 = Order.count
c2 = Order.count(["name = ?", "Dave Thomas"])
c3 = LineItem.count_by_sql("select count(*) from line_items, orders where line_items.order_id = orders.id and orders.name = 'Dave Thomas' ")
puts "Dave在#{c2}个定单里一共定了#{c3} 件商品 (目前定单总数:#{c1})"
动态查询
Ruby代码
order = Order.find_by_name("Dave Thomas")#只查一列
orders = Order.find_all_by_name("Dave Thomas")
order = Order.find_all_by_email(params['email'])
可同时查多个条件,如:
Ruby代码
user = User.find_by_name_and_password(name, pw)
重载数据库
Ruby代码
stock = Market.find_by_ticker("RUBY")
loop do
puts "Price = #{stock.price}"
sleep 60
stock.reload
end
更新数据
使用save()
Ruby代码
order = Order.find(123)
order.name = "Fred"
order.save
orders = Order.find_by_sql("select id, name, pay_type from orders where id=123")
first = orders[0]
first.name ="Wilma"
first.save
使用update_attribute()
Ruby代码
order = Order.find(123)
order.update_attribute(:name,"Barney")
order = Order.find(321)
order.update_attributes(:name => "Barney",
:email =>"[email protected]")
使用更快捷的update()
Ruby代码
order = Order.update(12, :name => "Barney", :email => "[email protected]")
使用update_all()
Ruby代码
result = Product.update_all("price = 1.1*price", "title like '%ruby%'")
Ruby代码
save()和save!()
save()
if order.save
# 成功
else
# 保存失败则...
end
Ruby代码
save!()
begin
order.save!
rescue RecordInvalid => error
# 保存失败RecordInvalid exception
end
数据锁(防止数据保存撞车)
加段:lock_version int default 0,
删除数据
Ruby代码
delete()删除
Order.delete(123)
User.delete([2,3,4,5])
Product.delete_all(["price > ?", @expensive_price])
destroy()冻结(在model层面)
Ruby代码
order = Order.find_by_name("Dave")
order.destroy
# ... order将被冻结
Ruby on Rails,使用where方法对持久化对象进行条件查询
http://www.cnblogs.com/abbuggy/archive/2012/10/21/2732868.html
在《Ruby on Rails,使用find方法加载持久化对象》一文中,我们使用find系列方法进行对象查询。在新版本的Rails中,都推荐使用where而不是find方法进行条件查询了。
语法上和find条件查询差不多,应该说更简洁一点,比如我想找到position是2的对象。
1
2
3
4
|
irb(main):
090
:
0
> Subject.where(
"position=?"
,
"2"
).order(
"name"
)
=> [
#<Subject id: 4, created_at: "2012-10-20 15:14:07", updated_at: "2012-10-20 15:17:46", name: "Fourth Subject", posit
ion:
"2"
>,
#<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject"
, position:
"2"
>]
|
与find方法不同的是,where方法返回的结果不是数组而是ActiveRelation,这意味着我们可以基于当前的查询结果继续设置条件进行查询。
1
2
|
irb(main):
168
:
0
* Subject.where(
:position
=>
"2"
).
class
=> ActiveRecord::Relation
|
并且,通过to_sql方法我们能看到Rails将我们的条件转换成的SQL语句以便于调试。
1
2
|
irb(main):
169
:
0
> Subject.where(
:position
=>
"2"
).to_sql
=>
"SELECT `subjects`.* FROM `subjects` WHERE `subjects`.`position` = '2'"
|
比如第一步先检索出position是2的所有对象,然后再根据name降序排列等等。
1
2
3
4
|
irb(main):
096
:
0
> Subject.where(
"position=?"
,
"2"
).order(
"name desc"
)
=> [
#<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject", posit
ion:
"2"
>,
#<Subject id: 4, created_at: "2012-10-20 15:14:07", updated_at: "2012-10-20 15:17:46", name: "Fourth Subject"
, position:
"2"
>]
|
与find的另一点不同是,where是懒加载的。也就可以理解为通过where方法返回对象只是一个壳子,里面什么都没有,直到我们需要从这个对象中取得属性值这一刻才会真的查询数据库。如果想要关闭懒加载特性,在where调用之后增加.all即可。
下面说说where方法中的条件参数格式。
第一种是String,相当于直接传入SQL语句,为了防止SQL注入的风险,最好只用于硬编码或变量全部由我们自己控制的SQL语句,千万不要将用户输入的变量值直接放在语句里。
1
2
3
|
irb(main):
160
:
0
> Subject.where(
"position = '2' AND name='Second Subject'"
)
=> [
#<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject", posit
ion:
"2"
>]
|
第二种是Array,第一个参数和需要写的SQL语句格式完全一样,字段值的地方用?问号代替。后面的参数按照顺序提供条件值。
1
2
3
|
irb(main):
161
:
0
> Subject.where(
"position = ? AND name=?"
,
"2"
,
"Second Subject"
)
=> [
#<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject", posit
ion:
"2"
>]
|
第三种是Hash,每个参数都是一套值对。这种方式非常简单直观,不过有点局限就是表现力有点差,只能表示AND,无法表示OR。
1
2
3
|
irb(main):
165
:
0
> Subject.where(
:position
=>
"2"
,
:name
=>
"Second Subject"
)
=> [
#<Subject id: 2, created_at: "2012-10-20 06:25:27", updated_at: "2012-10-20 15:10:36", name: "Second Subject", posit
ion:
"2"
>]
|
所以选择用哪种条件表达式方式就得根据实际情况而定了,一般来说简单的查询使用Hash方式,当复杂性无法满足的时候使用Array型。至于String方式直接写SQL语句的最好还是别用了。
查询返回的结果可以当做一个Array使用,如果什么都没查到,返回的长度为0。
1
2
|
irb(main):
172
:
0
> Subject.where(
:position
=>
"3"
)
=> []
|
http://blog.csdn.net/remote_roamer/article/details/23918303
rails 中 不利用 model 来进行动态 sql 运行的几种方法。
一. 依然利用任意一个model 的 find_by_sql() 来执行。
@result = Testmodels.findby('select ....') .
结果可以进行 json 化. @result.to_josn
二. 利用ActiveRecord::Base.connection.execute 来执行,获取sql语句返回的metadata
@result = ActiveRecord::Base.connection.execute ‘select...."
三. 利用
ActiveRecord::Base.connection.select_all ’sql_string。。。。‘ 的方法来获得metadata和结果集数组的 对象