`
jbf034
  • 浏览: 152377 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

CRUD—Read

阅读更多
从数据库中读取数据首先就要涉及到确定你所关心的特定的数据行--你必须给Active
Record 一些条件值,它将返回包含匹配数据行的对象。
查找表中的一行记录最简单的方法是指定它的主键。每个model 类都支持find()方法,
它接受一个或多个主键的值作为参数。如果只是给定一个主键,它返回一个对象,该对象包
含对应记录行的数据(或者是抛出RecordNotFound 异常)。如果给定了多个主键,find()返回一个对应的对象数组。注意在这种情况下,如果任何一个id 没有找到(所以如果方法返回并没引发一个错误,结果数据的长度将等于被做为参数传递的id 数量),就会返回RecordNotFound 异常。
an_order = Order.find(27) # find the order with id == 27
# Get a list of order ids from a form, then
# sum the total value
order_list = params[:order_ids]
orders = Order.find(order_list)
count = orders.size
1、
虽然,通常你需要读入基于一定标准而不是它们主键值的行。Active Record 对完成这
些查询提供了一个范围选项。我们开始查看低级的find()方法,并最终走向高级的动态查找。到现在为止,我们只是在表面上接触find()方法,使用它来返回一或多个基于我们做为
参数传递给它的id 的行。但是,find()还有一些微秒的性格。如果你传递符号:first 或:all
做为第一个参数,则原本不起眼的find()会变成强大的搜索机器。
find()的:first 变量返回匹配一定标准的第一行,而:all 则返回一个匹配行的数组。这
两种形式接受一组关键字参数,这些参数控制它们能做什么。但在我们查看这些之前,我们
需要花几页来解释Active Record 是如何处理SQL 的。
2、
SQL and Active Record
要演示Active Record 如何使用SQL 的,让我们行看看
find(:all,:conditions=>...)
方法调用中的:conditons 参数。这个:conditions 参数决定了find()返回那些记录行,它对应着SQL 的where 子句。比如,要返回符全付款类型”po”的所有order 列表给Dave,你应该使用pos = Order.find(:all,:conditions => "name = 'dave' and pay_type = 'po'")
结果是所有匹配记录的一个数组。每一个都被包装成Order 对象。如果没有orders 匹配
这个条件,数组将是空的。最好你能将你的条件预先定义好,但是怎样处理来自外部的客户名字的所在位置呢(也许来自一个web 表单)?一种途径是替换条件字符串中的那个变量值。
# get the limit amount from the form
name = params[:name]
# DON'T DO THIS!!!
pos = Order.find(:all,:conditions => "name = '#{name}' and pay_type = 'po'")

但是上面的做法并不是好。为什么呢?因为它会导致你的数据库打开之后出现SQL 注射
攻击。更多的细节会在427 页的21 章节描述。现在只要知道从一个外部SQL 语句源来替换字符串,会将你的整个数据库暴露给全世界。相反,最安全的途径是产生动态的SQL 语句,并让Active Record 处理它。无论何时你都可以在传递一个包含SQL 语句的字符串的地方,你也可以传递一个数组。数组地第一个元素是个包含SQL 的字符串,用这个SQL,你可以嵌入占位符,它在运行中可以被数组的其他值所替换。

指定占位符的一个途径是在SQLl 中插入一个或多个问号。第一个问号标记它可被数组的
第二个元素代替,下一个被第三个代替,依次类推。例如,我们应该重写前面的查询为
name = params[:name]
pos = Order.find(:all,:conditions => ["name = ? and pay_type = 'po'", name])
你也可以使用有名字的占位符。每个占位符形同:name,并且对应的值是作为一个哈希表
来提供的,哈希表中的key 对应查询中的名字。
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}])

你还可以在简单些。因为params 可是个有效哈希表,你可以简单传递哈希表字面符给条
件就行了。
pos = Order.find(:all,:conditions => ["name = :name and pay_type = :pay_type", params])
不管你使用占位符的哪种形式,Active Record 都会小心处理在SQL 中出现的双引号和
转义的值。使用这种动态SQL 形式,Active Record 可避免SQL 注入攻击。

3、
现在已经知道了怎样指定查询条件,让我们关注由find(:first,...)和find(:all,...)
支持的各种选项。
首先,重要的是理解find(:first,...)生成一个与带有同样条件的find(:all,...)相同
的SQL 查询语句,区别就在于对结果集的限制是单行还是多行。我们在一个地方描述用于两
者的参数,并演示使用这些参数find(:all,…)。我们直接把第一个参数为:first 和:all 的finder 方法称作find()。
没有其他参数,finder 执行的是一个select from ...语句。带有:all 形参的返回表中
所有记录行,带有:first 形参的返回一行。不保证返回记录的次序
(因此Order.find(:first)没有必要返回由应用程序创建第一个定单)。
:conditions 参数让你指定传给由find()方法内SQL 的where 子句中用到的条件。这个
条件即可以是一个包含SQL 的字符串,也可以是包含SQL 和替换值的数组,正如前一章所描
述的。(从现在起,我们将不再特别提醒SQL 参数的区别,都假设方法即可以接受字符串也
可以接受数组。)
daves_orders = Order.find(:all, :conditions => "name = 'Dave'")
name = params[:name]
other_orders = Order.find(:all, :conditions => ["name = ?", name])
yet_more = Order.find(:all,
:conditions => ["name = :name and pay_type = :pay_type",params])

(:order)
SQL 不保证记录行以什么次序返回,除非你明确地给查询增加一个order by 子句。:
order 参数就是让你指定你通常添加到order by 关键字后面的条件。例如,下面查询将返回
所有Dave 的定单,第一排序是付款类型,然后是发货日期(升序)。
orders = Order.find(:all,
:conditions => "name = 'Dave'",
:order => "pay_type, shipped_at DESC")

(:limit)
你还可以使用:limit 参数,限制find(:all,...)返回的记录行的数目。如果你使
用:limit 参数,你或许也想指定排序以确保得到一致的结果。例如,下面返回前10 个匹配
的定单。
orders = Order.find(:all,
:conditions => "name = 'Dave'",
:order => "pay_type, shipped_at DESC",
:limit => 10)

(:offset)减去偏移量剩下的数据
:offset 参数是要和:limit 参数一起使用的。它允许你指定由find()返回的结果集中第
一个记录的偏移量。
# The view wants to display orders grouped into pages,
# where each page shows page_size orders at a time.
# This method returns the orders on page page_num (starting
# at zero).
def Order.find_on_page(page_num, page_size)
find(:all,:order => "id",:limit => page_size,:offset => page_num*page_size)
end

(:joins)
finder 方法的:joins 参数可让你指定一个连接缺省表的附加表的一个列表。这个参数在
model 表名之后和条件之前被插入到SQL 中。join 语法是基于数据库形式的。下面代码返回
名为Programming Ruby 的书的所有商品项目列表。
LineItem.find(:all,:conditions => "pr.title = 'Programming Ruby'",
:joins => "as li inner join products as pr on li.product_id = pr.id")
就像我们在216 页14.6 节将看到的,你或许不想在find()使用:joins 参数--Active
Record 会为你处理大多数普通的表连接。

(:include)
还有一个额外的参数是,:include,如果你有关联定义的话,就要用到。我们234 页谈
论它。
find(:all,...)方法返回一个model 对象数组。相反如果你只想返回一个对象,可使用
find(:first,...)。它接受与:all 形式一样的参数,但是:limit 参数的值被强制设成1,所以只会有一行被返回。
# return an arbitrary order
order = Order.find(:first)
# return an order for Dave
order = Order.find(:first, :conditions => "name = 'Dave Thomas'")
# return the latest order for Dave
order = Order.find(:first,
:conditions => "name = 'Dave Thomas'",
:order => "id DESC")
如果给find(:first,…)使用条件,结果是从表中选择多行数据返回,这些记录的第一
被返回。如果没有行被选择,返回nil。

(find_by_sql)
find()方法可为你构造一个完整的SQL 查询语句。而find_by_sql()方法则允许你的应
用程序获得更完全的控制。它只接受包含SQL 的select 语句作为唯一参数,并且从结果集中
返回一个model 对象数组(可能空的)。这些model 的属性由查询返回得到的结果列名设置。
你通常可以使用select * 形式返回表的所有列,但这不必须的。[如果你的查询中使用主键
列,你会失败,你不能写从model 返回到数据库的update 语句。看276 页的15.7 节。]
orders = LineItem.find_by_sql("select line_items.* from line_items, orders "+" where order_id = orders.id " +
" and orders.name = 'Dave Thomas' ")

(attributes,attribute_names,attribute_presents?)
只有从查询中返回的这些属性才能在结果的model 对象中使用。你可以使用
attributes(),attribute_names(),attribute_present?()等方法来看model 对象哪些属性可用。第一个返回一个属性的(名/值)对的哈希表,第二个是名字数组,第三个是如果一个有名字的属性在model 可用的话,返回true。
orders = Order.find_by_sql("select name, pay_type from orders")
first = orders[0]
p first.attributes
p first.attribute_names
p first.attribute_present?("address")
这是输出
{"name"=>"Dave Thomas", "pay_type"=>"check"}
["name", "pay_type"]
false

find_by_sql()也可以通过包含派生出来的列数据创建model 对象。如果你使用as xxx
的SQL 语法给定结果集中的一个列的名字,这个名字就将成为属性名。
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}"
你也可以给find_by_sql()带上条件,即传递一个数组,第一个元素是一个包含占位符
的字符串。数组余下的部分即可以是哈希表也可以是用于替换的哈希表的字面值列表。
Order.find_by_sql(["select * from orders where amount > ?",
params[:amount]])

(count,count_by_sql)
Counting Rows
Aactive Record 定义了两个类方法来返回匹配的记录行数。count()返回匹配给定条件
的行数,没有条件给出所有行。count_by_sql()返回由sql 语句( select count(*) from ...)
生成的行数。
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 has #{c3} line items in #{c2} orders (#{c1} orders in
all)"

Dynamic Finders
可能在数据库中最通常的查找是根据匹配的列值返回记录行。一个查询可能返回所有记
录给Dave,或者是所有符合主题”Rails”的记录。在其他语言和框架中,你要构造SQL 语
句执行这些查找。Active Record 则充分使用Ruby 强大的动态特性来为你做这些。
例如,我们的Order model 有以下属性如:name,email,和address。我们可以在finder方法中使用这些名字,并返回那些相应匹配这些值的列的记录行。
order = Order.find_by_name("Dave Thomas")
orders = Order.find_all_by_name("Dave Thomas")
order = Order.find_all_by_email(params['email'])
如果你调用一个model 的类方法,它的名字以find_by_或find_all_by 开头的话,Active Record 会把它转换成一个finder,并使用方法名的余下部分来决定哪些列会被检查。因此下面这个调用
order = Order.find_by_name("Dave Thomas", other args...)
会由Active Record 有效地转换成
order = Order.find(:first,
:conditions => ["name = ?", "Dave
Thomas"],other_args...)
类似的,调用find_all_by_xxx 转换成find(:all,...)调用。
这种魔术并不止这些。Active Record 还将创建查找多列的finder 方法。例如,你可以

user = User.find_by_name_and_password(name, pw)
它相当于
user = User.find(:first,
:conditions => ["name = ? and password = ?", name, pw])
为决定要查询的列名,Active Record 简单地把find_by_或者find_all_by_所环绕的字
符串_and_的名字进行分解。这对大多数时侯是有效的,除非你有诸如tax_and_shipping 的
列名。这种情况下,你必须遵守finder 方法的命名约定。
目前为止,没有find_by_格式来让你在列名字之间使用_or_而不是_and_。
重新加载数据
在一个应用程序中,它的数据库很可能潜在被多个进程访问(或被多个应用程序访问),
在这些应用中总是存在这种可能:获取的model 对象已经是很久以前的数据了--因为有人已
经把新值写入了数据库。
这个问题可由事务处理机制(在237 页讨论它)来解决。但还是有可能需要人工的来更新
model 对象。Active Record 使得这种事情变得很容易,只需简单地调用reload()方法,并且对象的属性将马上从数据库中得到更新。
stock = Market.find_by_ticker("RUBY")
loop do
puts "Price = #{stock.price}"
sleep 60
stock.reload
end
根据实践来看,reload()基本上是在测试单元中使用,其他情况很少使用。
分享到:
评论

相关推荐

    CRUD CRUD CRUD

    CRUD,全称为Create(创建)、Read(读取)、Update(更新)和Delete(删除),是数据库操作的基础,也是理解任何数据驱动应用的核心概念。在IT行业中,CRUD操作广泛应用于各种应用程序,从简单的数据库管理工具到...

    jsp 实现的CRUD

    在Web开发中,CRUD(Create, Read, Update, Delete)是最基本的数据操作,广泛应用于各种业务系统。本项目以JSP(JavaServer Pages)技术为核心,实现了对MySQL数据库的CRUD操作,旨在提供一个完整的、可直接运行的...

    CRUD项目核心框架

    CRUD,全称为Create(创建)、Read(读取)、Update(更新)和Delete(删除),是数据库操作的基础,也是软件开发中的核心概念。在IT行业中,CRUD项目通常指的是一个以处理这些基本数据操作为主的系统或应用。在这个...

    SimpleThinkPHP_CRUD_Demo

    在IT领域,CRUD(Create, Read, Update, Delete)是数据库操作的基础,它代表了创建、读取、更新和删除数据的基本功能。SimpleThinkPHP_CRUD_Demo是一个以ThinkPHP框架为基础,实现CRUD操作的示例项目,对于初学者...

    Crud订单表操作

    在IT行业中,CRUD(Create, Read, Update, Delete)是数据库操作的四个基本功能,分别代表创建、读取、更新和删除数据。本压缩包文件"Crud订单表操作"显然是针对订单表进行CRUD操作的一个示例或教程,可能包含相关的...

    用Struts实现Table的CRUD(create、read、update、delete)

    在这个项目中,我们专注于使用Struts2来实现一个数据表的CRUD操作,包括创建(Create)、读取(Read)、更新(Update)和删除(Delete)。 首先,我们需要配置Struts2的核心框架。在`struts.xml`配置文件中,定义...

    原生servlet_CRUD

    原生Servlet CRUD是Java Web开发中的基础操作,主要用于创建、读取、更新和删除(Create, Read, Update, Delete)数据。在这个项目中,开发者直接使用了Servlet API进行实践,而不是依赖任何高级框架如Spring MVC。...

    struts_crud

    CRUD,即Create(创建)、Read(读取)、Update(更新)和Delete(删除),是数据库操作的基本功能,也是任何数据管理应用的核心部分。在Struts框架中实现CRUD操作,可以让我们更高效地开发Web应用。 Struts的CRUD...

    easyUI的crud实现

    它的CRUD(Create、Read、Update、Delete)实现是指使用EasyUI来完成数据的创建、读取、更新和删除功能,这些是任何数据管理应用的基础操作。在这里,我们将深入探讨如何使用EasyUI和Java来实现这一目标。 首先,让...

    完整的CRUD数据库操作

    CRUD,全称为Create(创建)、Read(读取)、Update(更新)和Delete(删除),是数据库管理系统中最基本的操作,涵盖了对数据库数据的所有基本交互。本文将深入探讨这些概念,并结合实际例子,帮助你理解如何在不同...

    struts2CRUD

    Struts2 CRUD是一个基于Apache Struts2框架实现的创建、读取、更新和删除(Create, Read, Update, Delete)操作的示例项目。这个项目主要用于演示如何在Web应用程序中使用Struts2来处理基本的数据操作。Struts2是...

    S2SH-CRUD整合框架

    SSH2 CRUD框架是基于Spring、Struts2和Hibernate三个开源组件构建的,主要用于简化Web应用中的数据操作,即增(Create)、删(Delete)、改(Update)和查(Read)功能。这个框架组合为开发者提供了高效、灵活和可...

    jsp简单明了实现CRUD

    在IT行业中,CRUD(Create, Read, Update, Delete)是数据库操作的四个基本功能,分别代表创建、读取、更新和删除数据。本案例主要介绍如何使用JSP(JavaServer Pages)技术来实现这些功能,这对于Web开发来说是基础...

    JSF实现的CRUD例子 myeclipse

    在这个"JSF实现的CRUD例子 myeclipse"中,我们将探讨如何使用JSF和MyEclipse开发一个简单的CRUD(Create, Read, Update, Delete)应用,而无需连接到数据库。 首先,"first-java-server-faces-tutorial-en.pdf"可能...

    SSH整合开发CRUD

    在本项目"SSH整合开发CRUD"中,我们将探讨如何将这三大框架整合起来,实现完整的创建(Create)、读取(Read)、更新(Update)和删除(Delete)功能。 Spring框架作为核心,它提供了依赖注入(Dependency ...

    SQLite CRUD

    在本文中,我们将深入探讨SQLite中的CRUD(创建Create、读取Read、更新Update、删除Delete)操作,特别是在处理多个表时的应用。 创建(Create): 在SQLite中,创建新表涉及编写SQL的CREATE TABLE语句。例如,如果...

    Laravel开发-crud-generator

    Laravel CRUD Generator能够帮助开发者快速创建CRUD(Create, Read, Update, Delete)操作,极大地提高了开发效率,降低了重复劳动。 Laravel是一个基于PHP的优雅且强大的Web应用开发框架,它的核心理念是"简洁、...

    VB实现的CRUD例子

    标题“VB实现的CRUD例子”表明这是一个使用Visual Basic (VB)编程语言创建的应用程序,主要功能是实现数据库操作的基本功能:创建(Create),读取(Read),更新(Update)和删除(Delete),简称CRUD。在数据库应用开发中...

    restful-crud-实验.tar.gz

    这个名为"restful-crud-实验.tar.gz"的压缩包文件显然是一个教学资源,旨在帮助学习者理解如何在SpringBoot应用中实现基于REST的创建(Create)、读取(Read)、更新(Update)和删除(Delete)功能。 首先,我们要...

Global site tag (gtag.js) - Google Analytics