当前位置: 首页 > 文档资料 > FuelPHP 中文文档 >

简介 - 關聯 - Orm 套件

优质
小牛编辑
117浏览
2023-12-01

Orm 是 物件关联对映(Object Relational Mapper) 的简写,它做两件事:
对应你资料库里的资料列到物件, 并能让你在这些物件之间建立关係。
它紧随 活动记录模式( Active Record Pattern),但也受到其他系统的影响。

关联:简介

配置

基本配置

protected static $_has_many = array('comments');

This example, if specified in Model_Article, enables fetching of an array of Model_Comment objects which have the field article_id matching the primary key of a given Article instance through the property comments.

完整配置

protected static $_has_many = array('comments' => array(
	'model_to' => 'Model_Fancy_Comment',
	'key_from' => 'article_id',
	'key_to' => 'parent_article_id',
	'cascade_save' => true,
	'cascade_delete' => false,
	// 还有给特定关联类型的一些选项
));

In the basic example, Orm automatically assumes the model name and field mapping. This example explicitly specifies the class name of the target model, the fields used to relate them, and whether actions performed on the current object should be cascaded to the target. It will return an array of Model_Fancy_Comment object where the comment's parent_article_id field corresponds to the current object's article_id. When saving an object the operation is also performed on its loaded relations, deleting isn't cascaded by default but can be if you switch this on.

There is a limitation when fetching relations and limiting their output: you can't use complex where statements on the main object. That are queries using parenthesis for nesting conditions using where_open(). Normal (non-nested) where queries can be applied without problems.
Technically it works like this: to limit the output the query on the base model's table is actually a subquery with a limit set on it. Any of those nested where conditions are applied on the result of the subquery and further joined relations.

配置选项

All of the configurations are optional when using the most common naming conventions.

选项预设注释
model_toCalculated from aliasIf specified, must the the full class name of the target model (ex. Model_Comment).
By default, this value is formed by prepending 'Model_' to the singular form of the alias (ex. 'comments' becomes 'Model_Comment'). If your model is in another namespace, you must specify the full namespace, excluding the leading backslash (ex. 'Admin\Model_User'), PHP doesn't support relative namespaces in strings.
key_fromThe key used for the relation in the current model (Usually id)Allows mapping the target model to an arbitrary field in the current model's table
key_toCalculated from the current model nameBy default, a relationship from a Model_Article to many Model_Comments would use the field article_id in the comments table
cascade_save布林 trueCascading means the operation on the model is repeated on its relation. Thus cascading a save will save the relations as well, cascading a delete will delete the relations as well. Be very careful with cascading delete!
You can override these options at runtime by passing true as the first argument when calling save() or delete() on the originating model.
cascade_delete布林 false
conditionsarray()Takes 'where' and 'order_by' keys. These are more limited than the normal usage: where must be an array of arrays containing array(field, compare, value). order_by contains an array of fields or associative field => direction.
Note: these are always used and cannot be turned off.

用法

The Orm allows for both eager and lazy-loading of relationships. Eager loading means that some (or all) relations are fetched in the original query. Lazy loading means that the relations aren't fetched until you request them.

// eager loading, using joins:
$post = Model_Post::find('all', array('related' => array('comments')));
// 或
$post = Model_Post::query()->related('comments')->get();
// $post->comments is available without any further querying after this

// or use lazy loading, it won't use joins but query a relation once requested
// first get a "post", 1 query without join
$post = Model_Post::find('first');
// now request the comments (not yet loaded), which will do another query without join automatically
$comments = $post->comments;

// alternatively, you can use get(), which allows additional conditions:
$comments = $post->get('comments', array('where' => array(array('field', '=', $value))));

使用 where/order_by 条件的用法

You can also additional conditions when fetching with the Orm. Note though that would also mean the data retrieved will only be valid to the conditions with which you fetched them.
Additional conditions are only possible with eager loading, though with lazy loading any default conditions (see config table above) will be used of course.

// 使用阵列查询
$post = Model_Post::find('first', array(
	'related' => array(
		'articles' => array(
'order_by' => array('id' => 'desc'),
'where' => array(
	array('publish_date', '>', time()),
	array('published', '=', 1),
),
		),
	),
));

// 使用方法鍊结
$post = Model_Post::query()->related('articles', array(
	'order_by' => array('id' => 'desc'),
	'where' => array(
		array('publish_date', '>', time()),
		array('published', 1), // 当使用 '=' 可以被省略
	),
)->get_one();

// but the same can also be done by prefixing the relation name to the column:
$post = Model_Post::query()->related('articles')
	->order_by('articles.id', 'desc')
	->where('articles.publish_date', '>', time())
	->where('articles.published', 1)
	->get_one();

使用巢状关联的用法

It is also possible to fetch the relations of relations to an unlimited depth (though you might want to be careful creating queries that require too many joins). All these can also be combined with where and order_by conditions, some are exemplified below.

Note that the order matters here, if you want to fetch the relations of a relation you must load the "parent" relation before its relation. Otherwise an exception will be thrown.

// 使用阵列查询
$post = Model_Post::find('first', array(
	'related' => array(
		'articles' => array(
'related' => array(
	'user' => array(
		'related' => array('profile'),
		'where' => array('active', 1),
	),
),
'order_by' => array(
	'published' => 'desc',
),
		),
	),
));

// 只使用方法鍊结
$post = Model_Post::query()
	->related('articles')
	->related('articles.user')
	->related('articles.user.profile')
	->where('articles.user.active', '=', 1)
	->order_by('articles.published', 'desc')
	->get_one();

// 或结合阵列&方法鍊结
$post = Model_Post::query()
	->related('articles', array(
		'related' => array('user' => array(
'where' => array('active' => 1),
		)),
		'order_by' => array('published', 'desc'),
	))
	->related('articles.user.profile')
	->get_one();

组合类型

预设情况下 Orm 将使用一个 'left' join 来组合关係。要指定一个不同的 join,利用 'join_type' 条件:

$post = Model_Post::find('first', array(
    'related' => array(
        'articles' => array(
        	'join_type' => 'inner',
            'where' => array(
                array('publish_date', '>', DB::expr(time())),
                array('published', '=', DB::expr(1)),
        	),
            'order_by' => array('id' => 'desc'),
        ),
    ),
));
	

Since 'where' clauses are executed before the JOIN is executed, you can not get a full OUTER JOIN results when you include a 'where' clause, it will act like a pre-join filter. The solution is to define the filter on the JOIN itself:

$post = Model_Post::find('all', array(
    'related' => array(
        'articles' => array(
            'join_type' => 'left outer',
            'join_on' => array(
                array('publish_date', '>', DB::expr(time())),
                array('published', '=', DB::expr(1)),
            ),
            'order_by' => array('id' => 'desc'),
        ),
    ),
));
	

This will make the selection criteria part of the ON clause, instead of the WHERE clause.

请注意,如果你想要传递一个字面值到一个加入,你将不得不把它封装在一个 DB::expr() 中,以避免它被转义为一个行名。

关联类型

Orm 原生支援以下关联类型:

  • Belongs To
    在其资料表中有关联的主键,属于一个关联物件。
  • Has One
    Has its primary key saved in one other row of another table (which belongs to this), has 1 related object.
  • Has Many
    Has its primary key saved in many other rows of another table (which belong to this one), has many related objects.
  • Many to Many
    Have their primary keys saved in a table in between which keeps pairs of primary keys from both tables. Have and belong to many objects.