yii2关系 Active Record Relation

Working with Relational Data
使用Relational Data(关系数据)
Besides working with individual database tables, Active Record is also capable of bringing together related data, making them readily accessible through the primary data. For example, the customer data is related with the order data because one customer may have placed one or multiple orders. With appropriate declaration of this relation, you may be able to access a customer's order information using the expression  $customer->orders which gives back the customer's order information in terms of an array of  Order Active Record instances.
AR除了能够操作独立的数据库表,它也同样的可以获取相关的数据,让它们就像主数据的附属品一样,比如说已和用户数据和对应的订单数据是一对多的关系,通过定义Relation(关系)就可以通过$customer->orders直接获取用户的订单列表了(订单对应AR的数组)。

Declaring Relations
定义(Relations)关系
To work with relational data using Active Record, you first need to declare relations in Active Record classes. The task is as simple as declaring a  relation method for every interested relation, like the following,
想要使用AR的数据关系,你首先要在AR中声明这些关系,这个工作非常简单,只要像下面这样,给对应的关系定义一个方法,说明AR之间的关系就可以了
class Customer extends ActiveRecord
{
public function
getOrders()
{
return
$this->hasMany(Order::className(), ['customer_id' => 'id']);
}
}

class
Order extends ActiveRecord
{
public function
getCustomer()
{
return
$this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
}
In the above code, we have declared an  orders relation for the  Customer class, and a  customer relation for the  Order class.
通过上面的代码来看,Customer这个AR中我们定义的orders关系,并且OrderAR中我们定义了customer关系
Each relation method must be named as  getXyz. We call  xyz (the first letter is in lower case) the  relation name. Note that relation names are  case sensitive.
每个关系方法都必须遵守命名约定,当你使用getXyz的函数名时,我们在使用的时候调用xyz(首字母变成小写)记住的是关系命名是大小写敏感的
While declaring a relation, you should specify the following information:
当你定一个关系,你需要指定一下的信息
  • the multiplicity of the relation: specified by calling either hasMany() or hasOne(). In the above example you may easily read in the relation declarations that a customer has many orders while an order only has one customer.
         对应关系的数量关系(一对多,一对一等):通过调用hasMany()(一对多)或者hasOne()(一对一)在上面的例子中,你可以轻松地理解关系是这样定义的:用户有很多订单,每个订单只属于一个用户

  • the name of the related Active Record class: specified as the first parameter to either hasMany() or hasOne(). A recommended practice is to call Xyz::className() to get the class name string so that you can receive IDE auto-completion support as well as error detection at compiling stage.
          对应关系的AR类名:这个值被放在了hasMany或hasOne的第一个参数,推荐你使用Xyz::className()这个方法来获取类名,这样你的开发环境更容易自动补充,也更容易找到编译错误

  • the link between the two types of data: specifies the column(s) through which the two types of data are related. The array values are the columns of the primary data (represented by the Active Record class that you are declaring relations), while the array keys are the columns of the related data.
          通过这个链接绑定这两种类型的数据:通过指定两个列使得两个类型的数据相互关联,这个数组(array)的值(value)是主数据(谁才是主数据呢?你正在给他定义关系方法的那个AR就是主数据。译者注:比如你给Customer定义orders关系,Customer就是主数据,当你使用一个Order的AR通过关系获取Customer的时候Order是主数据)的一个列,这个数据的键(key)是相关数据的列。

  • An easy rule to remember this is, as you see in the example above, you write the column that belongs to the related Active Record directly next to it. You see there that  customer_id is a property of  Order and  id is a property of  Customer.
         要记住这些,一个简单的规则就是像上面的例子一样,你写的列名属于它最靠近的那个AR。return $this->hasMany(Order::className(), ['customer_id' => 'id']);这一段中customer_id是数据它前面Order的.

Accessing Relational Data
操作关联数据
After declaring relations, you can access relational data through relation names. This is just like accessing an object  property defined by the relation method. For this reason, we call it  relation property. For example,
定义了关系之后,你就可以通过关联名操作关联数据了,这就和操作对象的属性一样,所以我们称之为 关系属性(relation property)。操作示例如下:
// SELECT * FROM `customer` WHERE `id` = 123
$customer = Customer::findOne(123);

// SELECT * FROM `order` WHERE `customer_id` = 123
// $orders is an array of Order objects
$orders = $customer->orders;
Info: When you declare a relation named  xyz via a getter method  getXyz(), you will be able to access  xyz like an  object property. Note that the name is case sensitive.
提示:当你定通过getXyz定义了一个名为xyz的关系之后,你就可以像操作对象属性一样直接操作xyz。注意名字大小写敏感
If a relation is declared with  hasMany(), accessing this relation property will return an array of the related Active Record instances; if a relation is declared with  hasOne(), accessing the relation property will return the related Active Record instance or null if no related data is found.
如果关系是通过hasMany()定义的,使用这个关系属性的时候得到的是个相关AR实例的数组;如果是通过hasOne()定义的,得到的是相关的AR实例,如果没找到则是null
When you access a relation property for the first time, a SQL statement will be executed, like shown in the above example. If the same property is accessed again, the previous result will be returned without re-executing the SQL statement. To force re-executing the SQL statement, you should unset the relation property first:  unset($customer->orders).
如果你是第一次使用关系属性,系统会执行一个sql语句,就像上面例子中一样。如果你再去使用这个属性,上一次的结果会被直接返回而并不需要再去执行一次sql语句。如果你想在执行一次你需要先把这个属性删除:unset($customer->orders)
Note: While this concept looks similar to the  object property feature, there is an important difference. For normal object properties the property value is of the same type as the defining getter method. A relation method however returns an  yii\db\ActiveQuery instance, while accessing a relation property will either return a  yii\db\ActiveRecord instance or an array of these.
注意:这个概念看起来像是对象属性,但事实上有着重要的不同。对于一般的对象属性,它的值和它的getter方法是同样的类型。对于关系属性,它的关系定义返回是一个yii\db\ActiveQuery实例,当你操作这个对象属性的时候它会返回一个yii\db\ActiveRecord或者数组(译者注或者null)
$customer->orders; // is an array of `Order` objects
$customer->getOrders(); // returns an ActiveQuery instance
This is useful for creating customized queries, which is described in the next section.
这样有助于创建自定义请求(query),这一点会在下一节展开

Dynamic Relational Query
动态的关系查询
Because a relation method returns an instance of  yii\db\ActiveQuery, you can further build this query using query building methods before performing DB query. For example,
因为一个关系方法返回的的是yii\db\ActiveQuery,这样你就可以在执行数据库操作之前通过查询构建方法(query building metohd)来进一步构建查询。如下面例子所示:
$customer = Customer::findOne(123);

// SELECT * FROM `order` WHERE `subtotal` > 200 ORDER BY `id`
$orders = $customer->getOrders()
->
where(['>', 'subtotal', 200])
->
orderBy('id')
->
all();
Unlike accessing a relation property, each time you perform a dynamic relational query via a relation method, a SQL statement will be executed, even if the same dynamic relational query was performed before.
和直接操作关系属性不同,这里通过每次使用关系方法执行一个动态的关系查询,不论之前是否执行过这个动态关系查询,这都会执行一个sql语句。
Sometimes you may even want to parametrize a relation declaration so that you can more easily perform dynamic relational query. For example, you may declare a  bigOrders relation as follows,
有时候你希望定制一个带参数的关系查询,这样你就能更方便的执行动态关系查询了。比如说你可以向下面这样定义一个bigOrders关系
class Customer extends ActiveRecord
{
public function
getBigOrders($threshold = 100)
{
return
$this->hasMany(Order::className(), ['customer_id' => 'id'])
->
where('subtotal > :threshold', [':threshold' => $threshold])
->
orderBy('id');
}
}
Then you will be able to perform the following relational queries:
这样你在使用关系查询的时候就可以像下面这么用了
// SELECT * FROM `order` WHERE `subtotal` > 200 ORDER BY `id`
$orders = $customer->getBigOrders(200)->all();

// SELECT * FROM `order` WHERE `subtotal` > 100 ORDER BY `id`
$orders = $customer->bigOrders;

Relations via a Junction Table

In database modelling, when the multiplicity between two related tables is many-to-many, a  junction table is usually introduced. For example, the  order table and the  item table may be related via a junction table named  order_item. One order will then correspond to multiple order items, while one product item will also correspond to multiple order items.
在数据库建模中,当关系的类型是多对多的时候,我们通常使用连接表(junction table)。比如说订单(order)表和物品(item)表通过一个链接表order_item关联,一个订单会有多个订单物品,一个物品同样会出现在多个订单中。

When declaring such relations, you would call either  via() or  viaTable() to specify the junction table. The difference between  via() and  viaTable() is that the former specifies the junction table in terms of an existing relation name while the latter directly the junction table. For example,
当我们定义这样的关系时,你需要使用via()或viaTable()方法来指定关系表。其中via和viaTable的不同之处在于前者指定的是关联表上已经有定义关系的情况,而后者直接使用关联表
class Order extends ActiveRecord
{
public function
getItems()
{
return
$this->hasMany(Item::className(), ['id' => 'item_id'])
->
viaTable('order_item', ['order_id' => 'id']);
}
}
or alternatively,
或者换成这样(译者注:上面是viaTable直接使用关联表数据做关联,下面是通过Order关联到OrderItem这个关系表之后再做的关联)
class Order extends ActiveRecord
{
public function
getOrderItems()
{
return
$this->hasMany(OrderItem::className(), ['order_id' => 'id']);
}

public function
getItems()
{
return
$this->hasMany(Item::className(), ['id' => 'item_id'])
->
via('orderItems');
}
}
The usage of relations declared with a junction table is the same as that of normal relations. For example,
通过关联表定义的关系使用方法如下:
// SELECT * FROM `order` WHERE `id` = 100
$order = Order::findOne(100);

// SELECT * FROM `order_item` WHERE `order_id` = 100
// SELECT * FROM `item` WHERE `item_id` IN (...)
// returns an array of Item objects
$items = $order->items;

Lazy Loading and Eager Loading
缓加载和预加载
In  Accessing Relational Data, we explained that you can access a relation property of an Active Record instance like accessing a normal object property. A SQL statement will be executed only when you access the relation property the first time. We call such relational data accessing method  lazy loading. For example,
在操作关联数据一节中,我们解释了如何像操作对象属性一样使用AR的关系属性,一个SQL语句会在你第一次使用这个属性的时候执行,我们称这种数据处理方式为缓加载,缓加载形式如下所示
// SELECT * FROM `customer` WHERE `id` = 123
$customer = Customer::findOne(123);

// SELECT * FROM `order` WHERE `customer_id` = 123
$orders = $customer->orders;

// no SQL executed
$orders2 = $customer->orders;
Lazy loading is very convenient to use. However, it may suffer from a performance issue when you need to access the same relation property of multiple Active Record instances. Consider the following code example. How many SQL statements will be executed?
缓加载使用起来是非常方便的,然而当你操作许多个AR实例的关系属性时就可能会遇到性能问题。考虑下下面代码中会需要执行多少个sql语句?
// SELECT * FROM `customer` LIMIT 100
$customers = Customer::find()->limit(100)->all();

foreach (
$customers as $customer) {
// SELECT * FROM `order` WHERE `customer_id` = ...
$orders = $customer->orders;
}
As you can see from the code comment above, there are 101 SQL statements being executed! This is because each time you access the  orders relation property of a different  Customerobject in the for-loop, a SQL statement will be executed.
你应该明白上面代码中的注释了,一共有101个sql语句被执行。这是因为在for循环中每一次操作Customer的关系属性orders的时候都会执行一个sql语句
To solve this performance problem, you can use the so-called  eager loading approach as shown below,
要解决这个问题,你可以使用下面这种预加载的方式
// SELECT * FROM `customer` LIMIT 100;
// SELECT * FROM `orders` WHERE `customer_id` IN (...)
$customers = Customer::find()
->
with('orders')
->
limit(100)
->
all();

foreach (
$customers as $customer) {
// no SQL executed
$orders = $customer->orders;
}
By calling  yii\db\ActiveQuery::with(), you instruct Active Record to bring back the orders for the first 100 customers in one single SQL statement. As a result, you reduce the number of the executed SQL statements from 101 to 2!
通过调用yii\db\ActiveQuery::with(),你指示AR通过一条语句带回了100个用户(customer)的所有order信息。所以你把sql查询的数量从101降到了2
You can eagerly load one or multiple relations. You can even eagerly load  nested relations. A nested relation is a relation that is declared within a related Active Record class. For example, Customer is related with  Order through the  orders relation, and  Order is related with  Item through the  items relation. When querying for  Customer, you can eagerly load  items using the nested relation notation  orders.items.
你可以预加载一个或多个关系,也可以预加载嵌套的关系。嵌套的关系就是说它是定义在关联的AR中的关系,举个例子就是Customer有orders有关系,Order有items关系,在你查询Customer的时候,你就可以通过迁到关系直接预加载orders.items的数据
The following code shows different usage of  with(). We assume the  Customer class has two relations  orders and  country, while the  Order class has one relation  items.
下面这段代码展示了如何使用with()方法。我们假设Customer类有两个关系分别是orders和country,同时Order类有个关系叫做items
// eager loading both "orders" and "country"
$customers = Customer::find()->with('orders', 'country')->all();
// equivalent to the array syntax below
$customers = Customer::find()->with(['orders', 'country'])->all();
// no SQL executed
$orders= $customers[0]->orders;
// no SQL executed
$country = $customers[0]->country;

// eager loading "orders" and the nested relation "orders.items"
$customers = Customer::find()->with('orders.items')->all();
// access the items of the first order of the first customer
// no SQL executed
$items = $customers[0]->orders[0]->items;
You can eagerly load deeply nested relations, such as  a.b.c.d. All parent relations will be eagerly loaded. That is, when you call  with() using  a.b.c.d, you will eagerly load  aa.ba.b.cand  a.b.c.d.
你可以预加载类似a.b.c.d这样深层嵌套的关系。所有的父级关系都会被预加载。也就是说,当你使用a.b.c.d调用with()的时候,你会预加载a,a.b,a.b.c和a.b.c.d
Info: In general, when eagerly loading  N relations among which  M relations are defined with a  junction table, a total number of  N+M+1 SQL statements will be executed. Note that a nested relation  a.b.c.d counts as 4 relations.
提示:一般来讲当你预加载N个关系,其中M个关系是通过关联表(junction table)定义的,总的sql查询数量将会是N+M+1。记住一个a.b.c.d这样的嵌套关系算作4个关系(译者注:最后这句搞的我反倒不懂了呢,是我英文还有待提升咩,还是说我不会数数了)
When eagerly loading a relation, you can customize the corresponding relational query using an anonymous function. For example,
当使用预加载关系的时候,你可以通过一个匿名函数定制对应的关系查询,如下面例子所示
// find customers and bring back together their country and active orders
// SELECT * FROM `customer`
// SELECT * FROM `country` WHERE `id` IN (...)
// SELECT * FROM `order` WHERE `customer_id` IN (...) AND `status` = 1
$customers = Customer::find()->with([
'country',
'orders' => function ($query) {
$query->andWhere(['status' => Order::STATUS_ACTIVE]);
},
])->
all();
When customizing the relational query for a relation, you should specify the relation name as an array key and use an anonymous function as the corresponding array value. The anonymous function will receive a  $query parameter which represents the  yii\db\ActiveQuery object used to perform the relational query for the relation. In the code example above, we are modifying the relational query by appending an additional condition about order status.
当你给一个关系自定义关联请求的时候,你需要指定一个键值对,键对应关系的名称,值则为相应的匿名函数。这个匿名函数会接收到一个用来执行关系查询的yii\db\ActiveQuery对象作为$query参数,我们通过追加关于订单状态(order.status)额外的条件修改了这个关系查询
Note: If you call  select() while eagerly loading relations, you have to make sure the columns referenced in the relation declarations are being selected. Otherwise, the related models may not be loaded properly. For example,
注意:如果你在预加载管子中调用select()方法,你必须保证关系相关的列都在select中提到。否则的话关联的AR将无法正确的加载,请看如下示例
$orders = Order::find()->select(['id', 'amount'])->with('customer')->all();
// $orders[0]->customer is always null. To fix the problem, you should do the following:
$orders = Order::find()->select(['id', 'amount', 'customer_id'])->with('customer')->all();

Joining with Relations
通过关系连接表
Note: The content described in this subsection is only applicable to relational databases, such as MySQL, PostgreSQL, etc.
注意:这个小节中提到的内容都仅限于关系型数据库,比如MySQL,PostgreSQL等
The relational queries that we have described so far only reference the primary table columns when querying for the primary data. In reality we often need to reference columns in the related tables. For example, we may want to bring back the customers who have at least one active order. To solve this problem, we can build a join query like the following:
目前我们所提到的关系查询都是在查询时仅查询主表的列来获取主数据,在现实需求中我们经常需要获取关联表中的列,比如说我们需要获取至少有一个订单的用户们,要解决这个问题,我们需要构建一个类似下面这样的关联查询
// SELECT `customer`.* FROM `customer`
// LEFT JOIN `order` ON `order`.`customer_id` = `customer`.`id`
// WHERE `order`.`status` = 1
//
// SELECT * FROM `order` WHERE `customer_id` IN (...)
$customers = Customer::find()
->
select('customer.*')
->
leftJoin('order', '`order`.`customer_id` = `customer`.`id`')
->
where(['order.status' => Order::STATUS_ACTIVE])
->
with('orders')
->
all();
Note: It is important to disambiguate column names when building relational queries involving JOIN SQL statements. A common practice is to prefix column names with their corresponding table names.
注意:区分列名在构建关系查询中引入join语句的情况非常重要。一般的实践方式是通过给列名追加对应的表名前缀
However, a better approach is to exploit the existing relation declarations by calling  yii\db\ActiveQuery::joinWith():
然而,更好的方式是通过采用yii\db\ActiveQuery::joinWith()方法利用现有的关系声明
$customers = Customer::find()
->
joinWith('orders')
->
where(['order.status' => Order::STATUS_ACTIVE])
->
all();
Both approaches execute the same set of SQL statements. The latter approach is much cleaner and drier, though.
尽管两个方式执行的结果都是相同的sql语句,显然后者看起来更干净简洁
By default,  joinWith() will use  LEFT JOIN to join the primary table with the related table. You can specify a different join type (e.g.  RIGHT JOIN) via its third parameter  $joinType. If the join type you want is  INNER JOIN, you can simply call  innerJoinWith(), instead.
默认的,joinWith()方法会使用left join来链接主表和关联表,你可以通过第三个参数$joinType指定一个不同的连表方式(比如 right join)如果你希望使用inner join,你可以直接使用innerJoinWith()方法
Calling  joinWith() will  eagerly load the related data by default. If you do not want to bring in the related data, you can specify its second parameter  $eagerLoading as false.
调用joinWith()方法默认会预加载相关的数据,如果你不希望加载相关的数据,你可以通过指定第二个参数$eagerLoading为false
Like  with(), you can join with one or multiple relations; you may customize the relation queries on-the-fly; you may join with nested relations; and you may mix the use of  with() and  joinWith(). For example,
和with()相类似,你可以链接一个或多个关系,你可以凭空去定制关系查询,也可以链接嵌套关系,也可以混合with()方法一起使用
$customers = Customer::find()->joinWith([
'orders' => function ($query) {
$query->andWhere(['>', 'subtotal', 100]);
},
])->
with('country')
->
all();
Sometimes when joining two tables, you may need to specify some extra conditions in the  ON part of the JOIN query. This can be done by calling the  yii\db\ActiveQuery::onCondition() method like the following:
有时候当你关联两个表的时候,你会需要指定一些额外的条件在on条件的部分。这可以像下面一样通过yii\db\ActiveQuery::onCondition()方法完成
// SELECT `customer`.* FROM `customer`
// LEFT JOIN `order` ON `order`.`customer_id` = `customer`.`id` AND `order`.`status` = 1
//
// SELECT * FROM `order` WHERE `customer_id` IN (...)
$customers = Customer::find()->joinWith([
'orders' => function ($query) {
$query->onCondition(['order.status' => Order::STATUS_ACTIVE]);
},
])->
all();
This above query brings back  all customers, and for each customer it brings back all active orders. Note that this differs from our earlier example which only brings back customers who have at least one active order.
上面这个查询返回了所有的用户和每个用户的订单。注意这里的不同,这里的用户都至少有一个active状态的订单

Info: When  yii\db\ActiveQuery is specified with a condition via  onCondition(), the condition will be put in the  ON part if the query involves a JOIN query. If the query does not involve JOIN, the on-condition will be automatically appended to the  WHERE part of the query.
提示:当yii\db\ActiveQuery通过onCondition指定了一个条件的时候,如果这个查询涉及了连表,这个条件会被放在ON的部分。如果这个查询并没有涉及到连表,那么这个条件会被追加到WHERE的部分

Inverse Relations
反向关系
Relation declarations are often reciprocal between two Active Record classes. For example,  Customer is related to  Order via the  orders relation, and  Order is related back to  Customer via the  customer relation.
关联定义在两个AR之间通常都是相互的,比如说用户通过orders关系关联到订单,订单通过customer关系关联到用户
class Customer extends ActiveRecord
{
public function
getOrders()
{
return
$this->hasMany(Order::className(), ['customer_id' => 'id']);
}
}

class
Order extends ActiveRecord
{
public function
getCustomer()
{
return
$this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
}
Now consider the following piece of code:
现在考虑如下的代码片段
// SELECT * FROM `customer` WHERE `id` = 123
$customer = Customer::findOne(123);

// SELECT * FROM `order` WHERE `customer_id` = 123
$order = $customer->orders[0];

// SELECT * FROM `customer` WHERE `id` = 123
$customer2 = $order->customer;

// displays "not the same"
echo $customer2 === $customer ? 'same' : 'not the same';
We would think  $customer and  $customer2 are the same, but they are not! Actually they do contain the same customer data, but they are different objects. When accessing  $order->customer, an extra SQL statement is executed to populate a new object  $customer2.
我们会认为$customer和$customer2是相同的,但他们并不相同。事实上他们都包含相同的用户信息,但是他们是不同的对象。当操作$order->customer的时候,执行了一个额外的sql查询并反悔了新的$customer2
To avoid the redundant execution of the last SQL statement in the above example, we should tell Yii that  customer is an  inverse relation of  orders by calling the  inverseOf() method like shown below:
为了避免重复的执行上面例子中的sql语句,我们需要通过调用inverseOf方法告诉Yii框架这个customer和orders是相反的关系,代码如下所示:
class Customer extends ActiveRecord
{
public function
getOrders()
{
return
$this->hasMany(Order::className(), ['customer_id' => 'id'])->inverseOf('customer');
}
}
With this modified relation declaration, we will have:
通过修改这个关系定义,我们将会获得:
// SELECT * FROM `customer` WHERE `id` = 123
$customer = Customer::findOne(123);

// SELECT * FROM `order` WHERE `customer_id` = 123
$order = $customer->orders[0];

// No SQL will be executed
$customer2 = $order->customer;

// displays "same"
echo $customer2 === $customer ? 'same' : 'not the same';
Note: Inverse relations cannot be defined for relations involving a  junction table. That is, if a relation is defined with  via() or  viaTable(), you should not call  inverseOf() further.
注意:反向关系无法在使用了关联表(junction table)的情况使用。也就是说凡是通过via()或者viaTable()定义的关系,都不要使用inverseOf()方法了

Saving Relations
保存关系
When working with relational data, you often need to establish relationships between different data or destroy existing relationships. This requires setting proper values for the columns that define the relations. Using Active Record, you may end up writing the code like the following:
当你使用关系数据的时候,你经常需要给不同的数据建立新关系或清除现有关系,这需要给对应的列设置对应的值,当你使用AR的时候,你再也不用写像下面这样的语句了
$customer = Customer::findOne(123);
$order = new Order();
$order->subtotal = 100;
// ...

// setting the attribute that defines the "customer" relation in Order
$order->customer_id = $customer->id;
$order->save();
Active Record provides the  link() method that allows you to accomplish this task more nicely:
AR给你提供了link()方法,让你更轻松地完成这个工作
$customer = Customer::findOne(123);
$order = new Order();
$order->subtotal = 100;
// ...

$order->link('customer', $customer);
The  link() method requires you to specify the relation name and the target Active Record instance that the relationship should be established with. The method will modify the values of the attributes that link two Active Record instances and save them to the database. In the above example, it will set the  customer_id attribute of the  Order instance to be the value of the  idattribute of the  Customer instance and then save it to the database.
link()方法需要你指定建立这个链接所需要的关系名称,和对应的AR实例目标。这个方法会修改连接两个AR的值并且保存到数据库。在上面那个例子中,它会将Order实例中的customer_id属性设置为Customer实例的id属性并保存到数据库
Note: You cannot link two newly created Active Record instances.
注意:你不能给两个新创建的AR实例建立连接(译者注:关联到的一定要先入库才有ID?是这个原因么)
The benefit of using  link() is even more obvious when a relation is defined via a  junction table. For example, you may use the following code to link an  Order instance with an  Item instance:
使用link方法的好处在你的关系使用关联表的时候更为明显,比方说你使用了下面的代码链接Order和Item的实例
$order->link('items', $item);
The above code will automatically insert a row in the  order_item junction table to relate the order with the item.
上面的代码会自动的在order_item表上插入一条记录来关联order和item
Info: The  link() method will NOT perform any data validation while saving the affected Active Record instance. It is your responsibility to validate any input data before calling this method.
提示:link方法在保存AR实例到数据库之前不会做任何验证,你需要负责在使用这个方法之前验证数据数据
The opposite operation to  link() is  unlink() which breaks an existing relationship between two Active Record instances. For example,
对应link相反的操作是unlink,这个方法会终止AR实例间的关系。如下所示
$customer = Customer::find()->with('orders')->all();
$customer->unlink('orders', $customer->orders[0]);
By default, the  unlink() method will set the foreign key value(s) that specify the existing relationship to be null. You may, however, choose to delete the table row that contains the foreign key value by passing the  $delete parameter as true to the method.
默认的,unlink方法会把现有关系的外键值设置为null,当然你也可以通过设置第三个参数$delete为true选择删掉对应包含外键的行。
When a junction table is involved in a relation, calling  unlink() will cause the foreign keys in the junction table to be cleared, or the deletion of the corresponding row in the junction table if $delete is true.
当关系使用了连接表的情况,调用unlink方法会导致关联表中的对应外键清空,或者如果$delete为true的情况对应的行会被删掉

Cross-Database Relations
跨库关系
Active Record allows you to declare relations between Active Record classes that are powered by different databases. The databases can be of different types (e.g. MySQL and PostgreSQL, or MS SQL and MongoDB), and they can run on different servers. You can use the same syntax to perform relational queries. For example,
AR允许你在两个AR在不同数据库的情况下定义AR之间的关系。数据库的类型也可以是不同的(比如说MySQL和PostgreSQL或者MS SQL和MongoDB)甚至,他们还运行在不同的服务器上。你都只需使用相同的语法来执行关系查询,举个例子:
// Customer is associated with the "customer" table in a relational database (e.g. MySQL)
class Customer extends \yii\db\ActiveRecord
{
public static function
tableName()
{
return
'customer';
}

public function
getComments()
{
// a customer has many comments
return $this->hasMany(Comment::className(), ['customer_id' => 'id']);
}
}

// Comment is associated with the "comment" collection in a MongoDB database
class Comment extends \yii\mongodb\ActiveRecord
{
public static function
collectionName()
{
return
'comment';
}

public function
getCustomer()
{
// a comment has one customer
return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
}

$customers = Customer::find()->with('comments')->all();
You can use most of the relational query features that have been described in this section.
你可以使用本小节描述的大部分关系型查询特性
Note: Usage of  joinWith() is limited to databases that allow cross-database JOIN queries. For this reason, you cannot use this method in the above example because MongoDB does not support JOIN.
注意:joinWith在跨库连表查询中是被限制使用的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值