active return会结束吗等于0吗

Included Modules
MULTI_VALUE_METHODS
[:includes, :eager_load, :preload, :select, :group,
:order, :joins, :left_joins, :left_outer_joins, :references,
:extending, :unscope]
SINGLE_VALUE_METHODS
[:limit, :offset, :lock, :readonly, :reordering,
:reverse_order, :distinct, :create_with]
CLAUSE_METHODS
[:where, :having, :from]
INVALID_METHODS_FOR_DELETE_ALL
[:limit, :distinct, :offset, :group, :having]
VALUE_METHODS
MULTI_VALUE_METHODS + SINGLE_VALUE_METHODS + CLAUSE_METHODS
Attributes
predicate_builder
Class Public methods
new(klass, table, predicate_builder, values = {})
def initialize(klass, table, predicate_builder, values = {})
@values = values
@offsets = {}
@loaded = false
@predicate_builder = predicate_builder
Instance Public methods
Compares two relations for equality.
def ==(other)
case other
when Associations::CollectionProxy, AssociationRelation
self == other.records
when Relation
other.to_sql == to_sql
when Array
records == other
Returns true if there are any records.
return super if block_given?
Returns true if relation is blank.
def blank?
records.blank?
build(*args, &block)
Alias for:
cache_key(timestamp_column = :updated_at)
Returns a cache key that can be used to identify the records fetched by
this query. The cache key is built with a fingerprint of the sql query, the
number of records matched by the query and a timestamp of the last updated
record. When a new record comes to match the query, or any of the existing
records is updated or deleted, the cache key changes.
Product.where(&name like ?&, &%Cosmic Encounter%&).cache_key
# =& &products/query-391b85b59-1-&
If the collection is loaded, the method will iterate through the records to
generate the timestamp, otherwise it will trigger one SQL query like:
SELECT COUNT(*), MAX(&products&.&updated_at&) FROM &products& WHERE (name like '%Cosmic Encounter%')
You can also pass a custom timestamp column to fetch the timestamp of the
last updated record.
Product.where(&name like ?&, &%Game%&).cache_key(:last_reviewed_at)
You can customize the strategy to generate the key on a per model basis
overriding ActiveRecord::Base#collection_cache_key.
def cache_key(timestamp_column = :updated_at)
@cache_keys ||= {}
@cache_keys[timestamp_column] ||= @klass.collection_cache_key(self, timestamp_column)
create(*args, &block)
Tries to create a new record with the same scoped attributes defined in the
relation. Returns the initialized object if validation fails.
Expects arguments in the same format as ActiveRecord::Base.create.
users = User.where(name: 'Oscar')
users.create # =& #&User id: 3, name: &Oscar&, ...&
users.create(name: 'fxn')
users.create # =& #&User id: 4, name: &fxn&, ...&
users.create { |user| user.name = 'tenderlove' }
# =& #&User id: 5, name: &tenderlove&, ...&
users.create(name: nil) # validation on name
# =& #&User id: nil, name: nil, ...&
def create(*args, &block)
scoping { @klass.create(*args, &block) }
create!(*args, &block)
Similar to , but calls create! on the
base class. Raises an exception if a validation error occurs.
Expects arguments in the same format as ActiveRecord::Base.create!.
def create!(*args, &block)
scoping { @klass.create!(*args, &block) }
delete(id_or_array)
Deletes the row with a primary key matching the id argument,
using a SQL DELETE statement, and returns the number of rows
deleted. Active Record objects are not instantiated, so the object's
callbacks are not executed, including any :dependent
association options.
You can delete multiple rows at once by passing an Array of ids.
Note: Although it is often much faster than the alternative, destroy, skipping callbacks might
bypass business logic in your application that ensures referential
integrity or performs other essential jobs.
# Delete a single row
Todo.delete(1)
# Delete multiple rows
Todo.delete([2,3,4])
def delete(id_or_array)
where(primary_key =& id_or_array).delete_all
delete_all()
Deletes the records without instantiating the records first, and hence not
calling the
nor invoking callbacks. This is a single SQL DELETE statement that goes
straight to the database, much more efficient than destroy_all. Be careful with
relations though, in particular :dependent rules defined on
associations are not honored. Returns the number of rows affected.
Post.where(person_id: 5).where(category: ['Something', 'Else']).delete_all
Both calls delete the affected posts all at once with a single DELETE
statement. If you need to destroy dependent associations or call your
before_* or after_destroy callbacks, use the destroy_all method instead.
If an invalid method is supplied, delete_all raises an
ActiveRecordError:
Post.limit(100).delete_all
# =& ActiveRecord::ActiveRecordError: delete_all doesn't support limit
def delete_all
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
value = get_value(method)
SINGLE_VALUE_METHODS.include?(method) ? value : value.any?
if invalid_methods.any?
raise ActiveRecordError.new(&delete_all doesn't support #{invalid_methods.join(', ')}&)
stmt = Arel::DeleteManager.new
stmt.from(table)
if has_join_values?
@klass.connection.join_to_delete(stmt, arel, arel_attribute(primary_key))
stmt.wheres = arel.constraints
affected = @klass.connection.delete(stmt, &SQL&, bound_attributes)
destroy(id)
Destroy an object (or multiple objects) that has the given id. The object
is instantiated first, therefore all callbacks and filters are fired off
before the object is deleted. This method is less efficient than delete but allows cleanup methods
and other actions to be run.
This essentially finds the object (or multiple objects) with the given id,
creates a new object from the attributes, and then calls destroy on it.
Parameters
id - Can be either an
of Integers.
# Destroy a single object
Todo.destroy(1)
# Destroy multiple objects
todos = [1,2,3]
Todo.destroy(todos)
def destroy(id)
if id.is_a?(Array)
id.map { |one_id| destroy(one_id) }
find(id).destroy
destroy_all()
Destroys the records by instantiating each record and calling its #destroy method. Each
object's callbacks are executed (including :dependent
association options). Returns the collection of objects that were
each will be frozen, to reflect that no changes should be made
(since they can't be persisted).
Note: Instantiation, callback execution, and deletion of each record can be
time consuming when you're removing many records at once. It generates
at least one SQL DELETE query per record (or possibly more, to
enforce your callbacks). If you want to delete many rows quickly, without
concern for their associations or callbacks, use delete_all instead.
Person.where(age: 0..18).destroy_all
def destroy_all
records.each(&:destroy).tap { reset }
eager_loading?()
Returns true if relation needs eager loading.
def eager_loading?
@should_eager_load ||=
eager_load_values.any? ||
includes_values.any? && (joined_includes_values.any? || references_eager_loaded_tables?)
Returns true if there are no records.
def empty?
return @records.empty? if loaded?
encode_with(coder)
Serializes the relation objects .
def encode_with(coder)
coder.represent_seq(nil, records)
Runs EXPLAIN on the query or queries triggered by this relation and returns
the result as a string. The string is formatted imitating the ones printed
by the database shell.
Note that this method actually runs the queries, since the results of some
are needed by the next ones when eager loading is going on.
Please see further details in the Active
Record Query Interface guide.
def explain
exec_explain(collecting_queries_for_explain { exec_queries })
find_or_create_by(attributes, &block)
Finds the first record with the given attributes, or creates a record with
the attributes if one is not found:
# Find the first user named &Penélope& or create a new one.
User.find_or_create_by(first_name: 'Penélope')
# =& #&User id: 1, first_name: &Penélope&, last_name: nil&
# Find the first user named &Penélope& or create a new one.
# We already have one so the existing record will be returned.
User.find_or_create_by(first_name: 'Penélope')
# =& #&User id: 1, first_name: &Penélope&, last_name: nil&
# Find the first user named &Scarlett& or create a new one with
# a particular last name.
User.create_with(last_name: 'Johansson').find_or_create_by(first_name: 'Scarlett')
# =& #&User id: 2, first_name: &Scarlett&, last_name: &Johansson&&
This method accepts a block, which is passed down to create. The last example above can
be alternatively written this way:
# Find the first user named &Scarlett& or create a new one with a
# different last name.
User.find_or_create_by(first_name: 'Scarlett') do |user|
user.last_name = 'Johansson'
# =& #&User id: 2, first_name: &Scarlett&, last_name: &Johansson&&
This method always returns a record, but if creation was attempted and
failed due to validation errors it won't be persisted, you get what create returns in such situation.
Please note *this method is not atomic*, it runs first a SELECT, and if
there are no results an INSERT is attempted. If there are other threads or
processes there is a race condition between both calls and it could be the
case that you end up with two similar records.
Whether that is a problem or not depends on the logic of the application,
but in the particular case in which rows have a UNIQUE constraint an
exception may be raised, just retry:
CreditAccount.transaction(requires_new: true) do
CreditAccount.find_or_create_by(user_id: user.id)
rescue ActiveRecord::RecordNotUnique
def find_or_create_by(attributes, &block)
find_by(attributes) || create(attributes, &block)
find_or_create_by!(attributes, &block)
Like find_or_create_by, but
calls create! so an
exception is raised if the created record is invalid.
def find_or_create_by!(attributes, &block)
find_by(attributes) || create!(attributes, &block)
find_or_initialize_by(attributes, &block)
Like find_or_create_by, but
calls new instead of create.
def find_or_initialize_by(attributes, &block)
find_by(attributes) || new(attributes, &block)
initialize_copy(other)
def initialize_copy(other)
@values = @values.dup
def inspect
subject = loaded? ? records : self
entries = subject.take([limit_value, 11].compact.min).map!(&:inspect)
entries[10] = &...& if entries.size == 11
&#&#{self.class.name} [#{entries.join(', ')}]&&
joined_includes_values()
Joins that are also marked for preloading. In which case we should just
eager load them. Note that this is a naive implementation because we could
have strings and symbols which represent the same association, but that
aren't matched by this. Also, we could have nested hashes which
partially match, e.g. { a: :b } & { a: [:b, :c] }
def joined_includes_values
includes_values & joins_values
load(&block)
Causes the records to be loaded from the database if they have not been
loaded already. You can use this if for some reason you need to explicitly
load some records before actually using them. The return value is the
relation itself, not the records.
Post.where(published: true).load # =& #&ActiveRecord::Relation&
def load(&block)
exec_queries(&block) unless loaded?
Returns true if there is more than one record.
return super if block_given?
limit_value ? records.many? : size & 1
new(*args, &block)
Initializes new record from relation while maintaining the current scope.
Expects arguments in the same format as ActiveRecord::Base.new.
users = User.where(name: 'DHH')
user = users.new # =& #&User id: nil, name: &DHH&, created_at: nil, updated_at: nil&
You can also pass a block to new with the new record as argument:
user = users.new { |user| user.name = 'Oscar' }
user.name # =& Oscar
Also aliased as:
def new(*args, &block)
scoping { @klass.new(*args, &block) }
Returns true if there are no records.
return super if block_given?
Returns true if there is exactly one record.
return super if block_given?
limit_value ? records.one? : size == 1
pretty_print(q)
def pretty_print(q)
q.pp(records)
Forces reloading of relation.
def reload
@last = @to_sql = @order_clause = @scope_for_create = @arel = @loaded = nil
@should_eager_load = @join_dependency = nil
@records = [].freeze
@offsets = {}
scope_for_create()
def scope_for_create
@scope_for_create ||= where_values_hash.merge(create_with_value)
Scope all queries to the current scope.
Comment.where(post_id: 1).scoping do
Comment.first
# =& SELECT &comments&.* FROM &comments& WHERE &comments&.&post_id& = 1 ORDER BY &comments&.&id& ASC LIMIT 1
Please check unscoped if you want to remove all previous scopes (including
the default_scope) during the execution of a block.
def scoping
previous, klass.current_scope = klass.current_scope(true), self
klass.current_scope = previous
Returns size of the records.
loaded? ? @records.length : count(:all)
Converts relation objects to .
records.dup
Returns sql statement for the relation.
User.where(name: 'Oscar').to_sql
# =& SELECT &users&.* FROM &users&
WHERE &users&.&name& = 'Oscar'
def to_sql
@to_sql ||= begin
relation = self
if eager_loading?
find_with_associations { |rel| relation = rel }
conn = klass.connection
conn.unprepared_statement {
conn.to_sql(relation.arel, relation.bound_attributes)
Updates an object (or multiple objects) and saves it to the database, if
validations pass. The resulting object is returned whether the object was
saved successfully to the database or not.
id - This should be the id or an array of ids to be updated.
attributes - This should be a hash of attributes or an array
of hashes.
# Updates one record
Person.update(15, user_name: 'Samuel', group: 'expert')
# Updates multiple records
people = { 1 =& { &first_name& =& &David& }, 2 =& { &first_name& =& &Jeremy& } }
Person.update(people.keys, people.values)
# Updates multiple records from the result of a relation
people = Person.where(group: 'expert')
people.update(group: 'masters')
Note: Updating a large number of records will run an UPDATE query for each
record, which may cause a performance issue. So if it is not needed to run
callbacks for each update, it is preferred to use update_all for updating all
records using a single query.
Updates all records in the current relation with details given. This method
constructs a single SQL UPDATE statement and sends it straight to the
database. It does not instantiate the involved models and it does not
trigger Active Record callbacks or validations. However, values passed to
will still go
through Active Record's normal type casting and serialization.
updates - A string, array, or hash representing the SET part
of an SQL statement.
# Update all customers with the given attributes
Customer.update_all wants_email: true
# Update all books with 'Rails' in their title
Book.where('title LIKE ?', '%Rails%').update_all(author: 'David')
# Update all books that match conditions, but limit it to 5 ordered by date
Book.where('title LIKE ?', '%Rails%').order(:created_at).limit(5).update_all(author: 'David')
# Update all invoices and set the number column to its id value.
Invoice.update_all('number = id')
def values
@values.dup
where_values_hash(relation_table_name = table_name)
Returns a hash of where conditions.
User.where(name: 'Oscar').where_values_hash
# =& {name: &Oscar&}
def where_values_hash(relation_table_name = table_name)
where_clause.to_h(relation_table_name)
Instance Protected methods
load_records(records)
def load_records(records)
@records = records.freeze
@loaded = true中国共产党第十七次全国代表大会
网站热线:2-829 新闻传真:5
东南新闻网版权所有,未经许可不得转载、建立镜像使用数据库: Active Record | The Definitive Guide to Yii | Yii PHP Framework
Documentation
Language & version
使用数据库
& Active Record &
Active Record
虽然 Yii DAO 可以处理几乎任何数据库相关的任务,
但很可能我们会花费 90% 的时间以编写一些执行普通 CRUD(create, read, update 和 delete)操作的 SQL 语句。
而且我们的代码中混杂了SQL语句时也会变得难以维护。要解决这些问题,我们可以使用 Active Record。
Active Record (AR) 是一个流行的 对象-关系映射 (ORM) 技术。
每个 AR 类代表一个数据表(或视图),数据表(或视图)的列在 AR 类中体现为类的属性,一个 AR 实例则表示表中的一行。
常见的 CRUD 操作作为 AR 的方法实现。因此,我们可以以一种更加面向对象的方式访问数据。
例如,我们可以使用以下代码向 tbl_post 表中插入一个新行。
$post=new Post;
$post-&title='sample post';
$post-&content='post body content';
$post-&save();
下面我们讲解怎样设置 AR 并通过它执行 CRUD 操作。我们将在下一节中展示怎样使用 AR 处理数据库关系。
为简单起见,我们使用下面的数据表作为此节中的例子。注意,如果你使用 MySQL 数据库,你应该将下面的 SQL 中的
AUTOINCREMENT 替换为 AUTO_INCREMENT。
CREATE TABLE tbl_post (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
title VARCHAR(128) NOT NULL,
content TEXT NOT NULL,
create_time INTEGER NOT NULL
注意: AR 并非要解决所有数据库相关的任务。它的最佳应用是模型化数据表为 PHP 结构和执行不包含复杂 SQL 语句的查询。
对于复杂查询的场景,应使用 Yii DAO。
1. 建立数据库连接
AR 依靠一个数据库连接以执行数据库相关的操作。默认情况下,
它假定 db 应用组件提供了所需的
数据库连接实例。如下应用配置提供了一个例子:
return array(
'components'=&array(
'db'=&array(
'class'=&'system.db.CDbConnection',
'connectionString'=&'sqlite:path/to/dbfile',
提示: 由于 Active Record 依靠表的元数据(metadata)测定列的信息,读取元数据并解析需要时间。
如果你数据库的表结构很少改动,你应该通过配置
属性的值为一个大于零的值开启表结构缓存。
对 AR 的支持受 DBMS 的限制,当前只支持下列几种 DBMS:
注意: 1.0.4 版开始支持
Microsoft SQL Server;从1.0.5 版开始支持 Oracle。
如果你想使用一个不是 db 的应用组件,或者如果你想使用 AR 处理多个数据库,你应该覆盖
类是所有 AR 类的基类。
提示: 通过 AR 使用多个数据库有两种方式。如果数据库的结构不同,你可以创建不同的 AR 基类实现不同的
。否则,动态改变静态变量
是一个好主意。
2. 定义 AR 类
要访问一个数据表,我们首先需要通过集成
定义一个 AR 类。
每个 AR 类代表一个单独的数据表,一个 AR 实例则代表那个表中的一行。
如下例子演示了代表 tbl_post 表的 AR 类的最简代码:
class Post extends CActiveRecord
public static function model($className=__CLASS__)
return parent::model($className);
public function tableName()
return 'tbl_post';
提示: 由于 AR 类经常在多处被引用,我们可以导入包含 AR 类的整个目录,而不是一个个导入。
例如,如果我们所有的 AR 类文件都在
protected/models 目录中,我们可以配置应用如下:
return array(
'import'=&array(
'application.models.*',
默认情况下,AR 类的名字和数据表的名字相同。如果不同,请覆盖
方法为每个 AR 类声明为如此(稍后解释)。
数据表行中列的值可以作为相应 AR 实例的属性访问。例如,如下代码设置了
title 列 (属性):
$post=new Post;
$post-&title='a sample post';
虽然我们从未在 Post 类中显式定义属性 title,我们还是可以通过上述代码访问。
这是因为 title 是 tbl_post 表中的一个列,CActiveRecord 通过PHP的 __get() 魔术方法使其成为一个可访问的属性。
如果我们尝试以同样的方式访问一个不存在的列,将会抛出一个异常。
AR 依靠表中良好定义的主键。如果一个表没有主键,则必须在相应的 AR
类中通过如下方式覆盖 primaryKey() 方法指定哪一列或哪几列作为主键。
public function primaryKey()
return 'id';
3. 创建记录
要向数据表中插入新行,我们要创建一个相应 AR 类的实例,设置其与表的列相关的属性,然后调用
方法完成插入:
$post=new Post;
$post-&title='sample post';
$post-&content='content for the sample post';
$post-&create_time=time();
$post-&save();
如果表的主键是自增的,在插入完成后,AR 实例将包含一个更新的主键。在上面的例子中,
id 属性将反映出新插入帖子的主键值,即使我们从未显式地改变它。
如果一个列在表结构中使用了静态默认值(例如一个字符串,一个数字)定义。则 AR
实例中相应的属性将在此实例创建时自动含有此默认值。改变此默认值的一个方式就是在 AR
类中显示定义此属性:
class Post extends CActiveRecord
public $title='please enter a title';
$post=new Post;
echo $post-&title;
记录在保存(插入或更新)到数据库之前,其属性可以赋值为
例如,为保存一个由 MySQL 的 NOW() 函数返回的时间戳,我们可以使用如下代码:
$post=new Post;
$post-&create_time=new CDbExpression('NOW()');
$post-&save();
提示: 由于 AR 允许我们无需写一大堆 SQL 语句就能执行数据库操作,
我们经常会想知道 AR 在背后到底执行了什么 SQL 语句。这可以通过开启 Yii 的
实现。例如,我们在应用配置中开启了
,我们将会在每个网页的最后看到执行过的 SQL 语句。
我们可以在应用配置中设置
,这样绑定在 SQL 语句中的参数值也会被记录。
4. 读取记录
要读取数据表中的数据,我们可以通过如下方式调用 find 系列方法中的一种:
$post=Post::model()-&find($condition,$params);
$post=Post::model()-&findByPk($postID,$condition,$params);
$post=Post::model()-&findByAttributes($attributes,$condition,$params);
$post=Post::model()-&findBySql($sql,$params);
如上所示,我们通过 Post::model() 调用 find 方法。
请记住,静态方法 model() 是每个 AR 类所必须的。
此方法返回在对象上下文中的一个用于访问类级别方法(类似于静态类方法的东西)的 AR 实例。
如果 find 方法找到了一个满足查询条件的行,它将返回一个 Post 实例,实例的属性含有数据表行中相应列的值。
然后我们就可以像读取普通对象的属性那样读取载入的值,例如
echo $post-&。
如果使用给定的查询条件在数据库中没有找到任何东西, find 方法将返回 null 。
调用 find 时,我们使用 $condition 和 $params 指定查询条件。此处
$condition 可以是 SQL 语句中的 WHERE 字符串,$params 则是一个参数数组,其中的值应绑定到 $condation
中的占位符。例如:
$post=Post::model()-&find('postID=:postID', array(':postID'=&10));
注意: 在上面的例子中,我们可能需要在特定的 DBMS 中将 postID 列的引用进行转义。
例如,如果我们使用 PostgreSQL,我们必须将此表达式写为 "postID"=:postID,因为 PostgreSQL
在默认情况下对列名大小写不敏感。
我们也可以使用 $condition 指定更复杂的查询条件。
不使用字符串,我们可以让 $condition 成为一个
的实例,它允许我们指定不限于 WHERE 的条件。
$criteria=new CDbCriteria;
$criteria-&select='title';
$criteria-&condition='postID=:postID';
$criteria-&params=array(':postID'=&10);
$post=Post::model()-&find($criteria);
注意,当使用
作为查询条件时,$params 参数不再需要了,因为它可以在
中指定,就像上面那样。
的方法是给 find 方法传递一个数组。
数组的键和值各自对应标准(criterion)的属性名和值,上面的例子可以重写为如下:
$post=Post::model()-&find(array(
'select'=&'title',
'condition'=&'postID=:postID',
'params'=&array(':postID'=&10),
当有多行数据匹配指定的查询条件时,我们可以通过下面的 findAll 方法将他们全部带回。
每个都有其各自的 find 方法,就像我们已经讲过的那样。
$posts=Post::model()-&findAll($condition,$params);
$posts=Post::model()-&findAllByPk($postIDs,$condition,$params);
$posts=Post::model()-&findAllByAttributes($attributes,$condition,$params);
$posts=Post::model()-&findAllBySql($sql,$params);
如果没有任何东西符合查询条件,findAll 将返回一个空数组。这跟 find 不同,find 会在没有找到什么东西时返回 null。
除了上面讲述的 find 和 findAll 方法,为了方便,(Yii)还提供了如下方法:
$n=Post::model()-&count($condition,$params);
$n=Post::model()-&countBySql($sql,$params);
$exists=Post::model()-&exists($condition,$params);
5. 更新记录
在 AR 实例填充了列的值之后,我们可以改变它们并把它们存回数据表。
$post=Post::model()-&findByPk(10);
$post-&title='new post title';
$post-&save();
正如我们可以看到的,我们使用同样的
方法执行插入和更新操作。
如果一个 AR 实例是使用 new 操作符创建的,调用
将会向数据表中插入一行新数据;
如果 AR 实例是某个 find 或 findAll 方法的结果,调用
将更新表中现有的行。
实际上,我们是使用
说明一个 AR 实例是不是新的。
直接更新数据表中的一行或多行而不首先载入也是可行的。 AR 提供了如下方便的类级别方法实现此目的:
Post::model()-&updateAll($attributes,$condition,$params);
Post::model()-&updateByPk($pk,$attributes,$condition,$params);
Post::model()-&updateCounters($counters,$condition,$params);
在上面的代码中, $attributes 是一个含有以 列名作索引的列值的数组;
$counters 是一个由列名索引的可增加的值的数组;$condition 和 $params 在前面的段落中已有描述。
6. 删除记录
如果一个 AR 实例被一行数据填充,我们也可以删除此行数据。
$post=Post::model()-&findByPk(10);
$post-&delete();
注意,删除之后, AR 实例仍然不变,但数据表中相应的行已经没了。
使用下面的类级别代码,可以无需首先加载行就可以删除它。
Post::model()-&deleteAll($condition,$params);
Post::model()-&deleteByPk($pk,$condition,$params);
7. 数据验证
当插入或更新一行时,我们常常需要检查列的值是否符合相应的规则。
如果列的值是由最终用户提供的,这一点就更加重要。总体来说,我们永远不能相信任何来自客户端的数据。
时, AR 会自动执行数据验证。
验证是基于在 AR 类的
方法中指定的规则进行的。
关于验证规则的更多详情,请参考
下面是保存记录时所需的典型的工作流。
if($post-&save())
当要插入或更新的数据由最终用户在一个 HTML 表单中提交时,我们需要将其赋给相应的 AR 属性。
我们可以通过类似如下的方式实现:
$post-&title=$_POST['title'];
$post-&content=$_POST['content'];
$post-&save();
如果有很多列,我们可以看到一个用于这种复制的很长的列表。
这可以通过使用如下所示的
属性简化操作。
更多信息可以在
一节找到。
$post-&attributes=$_POST['Post'];
$post-&save();
8. 对比记录
类似于表记录,AR 实例由其主键值来识别。
因此,要对比两个 AR 实例,假设它们属于相同的 AR 类, 我们只需要对比它们的主键值。
然而,一个更简单的方式是调用 。
提供了几个占位符方法,它们可以在子类中被覆盖以自定义其工作流。
: 这两个将在保存 AR 实例之前和之后被调用。
: 这两个将在一个 AR 实例被删除之前和之后被调用。
: 这个将在每个使用 new 操作符创建 AR 实例后被调用。
: 这个将在一个 AR 查找器被用于执行查询(例如 find(), findAll())之前被调用。
1.0.9 版本开始可用。
: 这个将在每个 AR 实例作为一个查询结果创建时被调用。
10. 使用 AR 处理事务
每个 AR 实例都含有一个属性名叫
的实例,这样我们可以在需要时配合 AR 使用由 Yii DAO 提供的
$model=Post::model();
$transaction=$model-&dbConnection-&beginTransaction();
$post=$model-&findByPk(10);
$post-&title='new post title';
$post-&save();
$transaction-&commit();
catch(Exception $e)
$transaction-&rollBack();
11. 命名范围
Note: 对命名范围的支持从版本 1.0.5 开始。
命名范围的最初想法来源于 Ruby on Rails.
命名范围(named scope) 表示一个 命名的(named) 查询规则,它可以和其他命名范围联合使用并应用于 Active Record 查询。
命名范围主要是在
方法中以名字-规则对的方式声明。
如下代码在 Post 模型类中声明了两个命名范围, published 和 recently。
class Post extends CActiveRecord
public function scopes()
return array(
'published'=&array(
'condition'=&'status=1',
'recently'=&array(
'order'=&'create_time DESC',
'limit'=&5,
每个命名范围声明为一个可用于初始化
实例的数组。
例如,recently 命名范围指定 order 属性为 create_time DESC ,
limit 属性为 5。他们翻译为查询规则后就会返回最近的5篇帖子。
命名范围多用作 find 方法调用的修改器。
几个命名范围可以链到一起形成一个更有约束性的查询结果集。例如,
要找到最近发布的帖子,
我们可以使用如下代码:
$posts=Post::model()-&published()-&recently()-&findAll();
总体来说,命名范围必须出现在一个 find 方法调用的左边。
它们中的每一个都提供一个查询规则,并联合到其他规则,
包括传递给 find 方法调用的那一个。
最终结果就像给一个查询添加了一系列过滤器。
注意: 命名范围只能用于类级别方法。也就是说,此方法必须使用 ClassName::model() 调用。
参数化的命名范围
命名范围可以参数化。例如,
我们想自定义 recently 命名范围中指定的帖子数量,要实现此目的,不是在 方法中声明命名范围,
而是需要定义一个名字和此命名范围的名字相同的方法:
public function recently($limit=5)
$this-&getDbCriteria()-&mergeWith(array(
'order'=&'create_time DESC',
'limit'=&$limit,
return $this;
然后,我们就可以使用如下语句获取3条最近发布的帖子。
$posts=Post::model()-&published()-&recently(3)-&findAll();
上面的代码中,如果我们没有提供参数 3,我们将默认获取 5 条最近发布的帖子。
模型类可以有一个默认范围,它将应用于所有
(包括相关的那些) 关于此模型的查询。例如,一个支持多种语言的网站可能只想显示当前用户所指定的语言的内容。
因为可能会有很多关于此网站内容的查询,
我们可以定义一个默认范围以解决此问题。
为实现此目的,我们覆盖
方法如下:
class Content extends CActiveRecord
public function defaultScope()
return array(
'condition'=&&language='&.Yii::app()-&language.&'&,
现在,如果下面的方法被调用,将会自动使用上面定义的查询规则:
$contents=Content::model()-&findAll();
注意,默认的命名范围只会应用于 SELECT 查询。INSERT, UPDATE 和 DELETE 查询将被忽略。
div class="revision">
Author: qiang.xue
Translators: riverlet, dongbeta
Yii Supporters
Copyright & 2017 by .
All Rights Reserved.

我要回帖

更多关于 c return 0 的文章

 

随机推荐