27、Active Record 基础(一)

原创 2006年05月22日 10:49:00

        Active RecordRails中提供的对象关系映射(ORM)层。在这一章,我们将看到Active Record的基础知识:连接数据库,映射表,操作数据等。 下一章我们将深入这些东西的细节中。

    Active Record非常接近标准的ORM模型:表对应类,行对应对象,列对应对象的属性。它在配置方面与大多数其他ORM框架不同。通过一组默认的规则,Aactive Record使得开发人员在配置上的工作非常小。要说明这一点,这儿有个程序,它使用Active Record包装MySQL数据库中的一个表orders。在用一个特定的id找到定单之前,它更改购买者的姓名,并将结果存回到数据库中,改变了原始记录行。

require "rubygems"

require_gem "activerecord"

ActiveRecord::Base.establish_connection(:adapter => "mysql",

:host => "localhost", :database => "railsdb")

class Order < ActiveRecord::Base

end

order = Order.find(123)

order.name = "Dave Thomas"

order.save

这就是全部的代码。在这个例子中没有要求任何配置信息(除了数据库连接)。Active Record是怎样知道我们所需要的,又是怎样知道正确地得到它呢?让我们看看这里面的原理。

 

14.1 表与类

 

当你创建一个ActiveRecord::Base的子类时,实际上是包装一个数据库表。缺省情况下,Active Record假定表名字是类名字的复数形式。如果类名包含多个以大写字母开头的单词,表名会假定以下划线分隔这些单词。一些无规律的复数形式也会被处理。

 

 

这些规则反应了DHHrails的作者)的理念:类名字应该是单数,而表名字应该是复数。如果你不喜欢这种做法,你可以在配置文件中设置一个全局变量关闭它(config目录下的environment.rb文件)

ActiveRecord::Base.pluralize_table_names = false

用于让表名字成为复数的算法很简单。多数时候它会正常工作,便如何你的类名字是Sheep,它会试着查找名为sheeps的表。对表名字和类名字的这种假设关系也可能会出问题,如果你用个先前的schema操作的话,[The meaning of the word schema varies across the industry. We use it to mean the definition of tables and their interrelationships in the context of an application or suite of related applications. Basically, the schema is the database structure required by your code. ]否则表的名字可能强迫你在代码中写陌生的和不合需要的类名字。基于这个原因,Active Record允许你使用set_table_name指令地覆写缺省生成的表名字。

class Sheep < ActiveRecord::Base

set_table_name "sheep" # Not "sheeps"

end

class Order < ActiveRecord::Base

set_table_name "ord_rev99_x" # Wrap a legacy table...

end

 

-------------------------------------------------------

David . . .

我的属性在哪儿?

 

The notion of a database administrator (DBA) as a separate role from programmer has led some developers to see strict boundaries between code and schema. Active Record blurs that distinction, and no other place is that more apparent than in the lack of explicit attribute definitions in the model.

But fear not. Practice has shown that it makes little difference whether you’re looking at a database schema, a separate XML mapping file, or inline attributes in the model. The composite view is similar to the separations already happening in the Model-View-Control pattern—just on a smaller scale.

Once the discomfort of treating the table schema as part of the model definition has dissipated, you’ll start to realize the benefits of keeping DRY. When you need to add an attribute to the model, you simply change the schema, which automatically retains your data (use alter instead of drop/create), and reload the application.

Taking the “build” step out of schema evolution makes it just as agile as the rest of the code. It becomes much easier to start with a small schema and extend and change it as needed.

--------------------------------------------------------

 

14.2 列与属性

 

Active Record对象对应数据库表中的行。对象的属性对应表中的列。你可能已经注意到我们定义的Order类并没有提到orders表中任何列。这是因为Active Record是在运行期间动态决定它们。Active Record在数据库端的schema上反射,以配置包装表的类。[这不是严格的事实,就像一个model可以有不是schema的一部分的属性。我们在272页的下一章将祥细讨论。]

我们的表orders可能是如下SQL语句创建的。

create table orders (

id int not null auto_increment,

name varchar(100) not null,

email varchar(255) not null,

address text not null,

pay_type char(10) not null,

shipped_at datetime null,

primary key (id)

);

我们创建一个包装这个表的Active Record类。

require 'rubygems'

require_gem 'activerecord'

# Connection code omitted...

class Order < ActiveRecord::Base

end

一旦我们定义了Order类,我们就可以查询到它包含的属性()的信息。下面的代码使用了columns()方法,它返回一个Column对象数组。这里我们只显示orders表的每个列的名字,通过一个hash导出shipped_at这个列的细节。

require 'pp'

pp Order.columns.map { |col| col.name }

pp Order.columns_hash['shipped_at']

当我们运行这段代码时,我们得到以下输出。

["id", "name", "email", "address", "pay_type", "shipped_at"]

#<ActiveRecord::ConnectionAdapters::Column:0x10e4a50

@default=nil,

@limit=nil,

@name="shipped_at",

@type=:datetime>

注意:Active Record决定每列的类型。在这个例子中,它已经知道数据库中的shipped_at列是一个datetime类型。它将从这个列得到的值存放在Ruby内的Time对象中。我们可以通过写入一个时间字符串到这个属性,然后再取回此内容来验证。你会发现它们返回的是Ruby Time对象。

order = Order.new

order.shipped_at = "2005-03-04 12:34"

pp order.shipped_at.class

pp order.shipped_at

它会产生:

Time

Fri Mar 04 12:34:00 CST 2005

14.1显示了SQL类型和它们的ruby表达方式之间的的映射关系。通常这个映射关系是显而易见的。只有一个潜在的与decimal列有关的问题。schema设计者会使用decimal列来存储带有固定小数位的数字--decimal列要求十分精确。Active Recorddecimal列映射为Float类。尽管这对大多数程序是可行的,但是浮点数字是不精确的,如果在这个类型的属性上执行一系列操作,可能会发生四舍五入的问题。你也可能想使用多个integer列来替代,存储货币值的各单元,分,角,元等。另一种做法是使用聚合来构造Money对象以便分离数据库的列(dollars centspounds pence,等)。

 

 

访问属性

 

如果一个model对象有个属性名为balance,你可以使用索引操作符,传递给它一个字符串或一个符号(symbol)来访问这个属性的值。这儿是我们将使用的符号。

account[:balance] #=> return current value

account[:balance] = 0.0 #=> set value of balance

尽管,在普通编码中不赞成这样使用,但是它可能会减少你的选择,当将来你可能对属性基础实现进行修改时。相反,你应该访问值或使用Ruby存取器方法来访问model属性。

account.balance #=> return current value

account.balance = 0.0 #=> set value of balance

使用这两种技术返回的值,如果可能话将被Active Record强制转换一个适当的Ruby类型(所以,例如,如果数据列是个timestamp,则一个Time对象将会被返回)。如果你想获得一个属性的原始值,append_before_type_case方法返回它的名字,像下面代码显示的。

account.balance_before_type_cast #=> "123.4", a string

account.release_date_before_type_cast #=> "20050301"

最后,在model本身的代码内部,你可使用read_attribute()write_attribute()私有方法。这些接受做为字符串参数的属性的名字。

 

------------------------------------------------

David . . .

覆写Model属性

这儿是个说明使用存取器获得model属性的好处的例子。我们的account model将立即引发个异常,只要是有人试图将balance设置成低于最小值的一个值。

class Account < ActiveRecord::Base

def balance=(value)

raise BalanceTooLow if value < MINIMUM_LEVEL

self[:balance] = value

end

end

 

 

 

 

 

 

 

 

Yii Framework 开发教程(27) 数据库-关联Active Record示例

 我们已经了解了怎样使用 Active Record (AR) 从单个数据表中获取数据。 在本节中,我们讲解怎样使用 AR 连接多个相关数据表并取回关联(join)后的数据集。 为了使...
  • zhouzhiwengang
  • zhouzhiwengang
  • 2014年01月19日 10:02
  • 378

ActiveRecord中实现软删除

软删除即不真正删除数据库中的数据,数据是可以恢复的,只是对用户来讲是不可见的。软删除在实际应用中很广泛,除了一般的论坛应用,在微博和微信之类的应用中也随处可见。为什么要有软删除而不是直接删除呢?个人认...
  • qwbtc
  • qwbtc
  • 2016年08月06日 11:57
  • 613

Active Record 设计模式原理及简单实现

Active Record 设计模式原理及简单实现 概述 本文简要介绍Active Record 设计模式。Active Record 是一种数据访问设计模式,它可以帮助你实现数据对象Object到关...
  • fanhengguang_php
  • fanhengguang_php
  • 2017年02月10日 10:49
  • 2336

零基础入门学习Python(27):模块和包

零基础入门学习Python(27):模块和包今天简单介绍一下Python的模块。 首先,我们知道容器是对数据的封装,函数是对语句的封装,类是对方法和属性的封装,而对于模块,它就是程序。Python有...
  • qq_33256568
  • qq_33256568
  • 2016年01月05日 16:02
  • 565

Rails学习笔记1(Active Record初探)

Active Record是MVC模型中的M,负责将代码中的对象的属性与数据表相连,这样无需编写SQL语句也可以实现数据的持久化。 Active Record提供了如下几个重要的功能: 表示模型和其...
  • exialym
  • exialym
  • 2016年03月02日 23:22
  • 393

3. Active Record(活动记录模式)

Active Record(活动记录)定义:在计算机领域中,表示编译器为每个被激活的函数分配的内存空间。 活动记录一般都存在栈中。因为栈结构比较简单,硬件能够支持。Active Record(中文名...
  • enlyhua
  • enlyhua
  • 2015年04月02日 16:10
  • 768

YII2-数据查询Active Record方法

查询数据 AR 提供了两种方法来构建 DB 查询并向 AR 实例里填充数据: •[[yii\db\ActiveRecord::find()]] •[[yii\db\ActiveRecord::f...
  • xmlife
  • xmlife
  • 2015年06月12日 14:52
  • 7433

代码回忆录:ThinkPHP随笔-基于ThinkPHP3.2.3

1. 概述 目录结构: 根目录结构 ThinkPHP/: 框架目录 Public/: 资源目录 Application/: 项目目录 index.php: 入口...
  • Fantastic_
  • Fantastic_
  • 2017年06月20日 10:25
  • 302

JFinal 源码超详细解析之DB+ActiveRecord

我记得以前有人跟我说,“面试的时候要看spring的源码,要看ioc、aop的源码"那为什么要看这些开源框架的源码呢,其实很多人都是"应急式"的去读,就像读一篇文章一下,用最快的速度把文章从头到尾读一...
  • zhao9tian
  • zhao9tian
  • 2014年07月29日 00:55
  • 3529

ruby on rails爬坑(二):Active Record数据库查询

一,相关资料不多说,精髓都在文档里。文档如下: - rails官方:Active Record 查询二,遇到的问题先说问题:#下面两条语句完成了相同的功能,可是性能有所差别 Mission.where...
  • code_for_free
  • code_for_free
  • 2016年02月05日 00:59
  • 708
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:27、Active Record 基础(一)
举报原因:
原因补充:

(最多只允许输入30个字)