Yii2模型的关联模型使用

Active Record 可以将相关数据集中进来, 使其可以通过原始数据轻松访问。 例如,客户数据与订单数据相关 因为一个客户可能已经存放了一个或多个订单。这种关系通过适当的声明, 你可以使用 $customer->orders 表达式访问客户的订单信息 这表达式将返回包含 Order Active Record 实例的客户订单信息的数组。

声明关联关系

你必须先在 Active Record 类中定义关联关系,才能使用 Active Record 的关联数据。 简单地为每个需要定义关联关系声明一个 关联方法 即可,如下所示,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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']);
}
}

上述的代码中,我们为 Customer 类声明了一个 orders 关联, 和为 Order 声明了一个 customer 关联。

每个关联方法必须这样命名:getXyz。然后我们通过 xyz(首字母小写)调用这个关联名。 请注意关联名是大小写敏感的。

当声明一个关联关系的时候,必须指定好以下的信息:

  • 关联的对应关系:通过调用 hasMany() 或者 hasOne() 指定。在上面的例子中,您可以很容易看出这样的关联声明: 一个客户可以有很多订单,而每个订单只有一个客户。
  • 相关联 Active Record 类名:用来指定为 hasMany() 或者 hasOne() 方法的第一个参数。 推荐的做法是调用 Xyz::className() 来获取类名称的字符串,以便您 可以使用 IDE 的自动补全,以及让编译阶段的错误检测生效。
  • 两组数据的关联列:用以指定两组数据相关的列(hasOne()/hasMany() 的第二个参数)。 数组的值填的是主数据的列(当前要声明关联的 Active Record 类为主数据), 而数组的键要填的是相关数据的列。

一个简单的口诀,先附表的主键,后主表的主键。 正如上面的例子,customer_idOrder 的属性,而 idCustomer 的属性。 (译者注:hasMany() 的第二个参数,这个数组键值顺序不要弄反了)

访问关联数据

定义了关联关系后,你就可以通过关联名访问相应的关联数据了。就像 访问一个由关联方法定义的对象一样,具体概念请查看 属性。 因此,现在我们可以称它为 关联属性 了。

1
2
3
4
5
6
// SELECT * FROM `customer` WHERE `id` = 123
$customer = Customer::findOne(123);

// SELECT * FROM `order` WHERE `customer_id` = 123
// $orders 是由 Order 类组成的数组
$orders = $customer->orders;

提示: 当你通过 getter 方法 getXyz() 声明了一个叫 xyz 的关联属性,你就可以像 属性 那样访问 xyz。注意这个命名是区分大小写的。

如果使用 hasMany()声明关联关系,则访问此关联属性 将返回相关的 Active Record 实例的数组; 如果使用 hasOne() 声明关联关系,访问此关联属性 将返回相关的 Active Record 实例,如果没有找到相关数据的话,则返回 null

当你第一次访问关联属性时,将执行 SQL 语句获取数据,如 上面的例子所示。如果再次访问相同的属性,将返回先前的结果,而不会重新执行 SQL 语句。要强制重新执行 SQL 语句,你应该先 unset 这个关联属性, 如:unset($ customer-> orders)

1
2
$customer->orders; // 获得 `Order` 对象的数组
$customer->getOrders(); // 返回 ActiveQuery 类的实例

设置别名

1
2
3
4
5
6
7
8
9
class Order extends ActiveRecord
{
// ...

public function getCustomer()
{
return $this->hasOne(Customer::className(), ['id' => 'customer_id'])->alias('c');
}
}

关联查询

1
2
3
4
5
$order = Order::find()->joinWith('customer')
->where(['filter1'=>$filter1, 'filter2'=>$filter2])
->andWhere(['=', 'c.filter3', $filter3])
->andWhere(['<=', 'cfilter4', $filter4])
->one();
坚持原创技术分享,您的支持将鼓励我继续创作!
0%