Laravel Eloquent ORM 中的多租户关系
Relationships in multi tenancy in Laravel Eloquent ORM
这又是一个跟进问题:
这一次我有关于在 eloquent 模型的多租户环境中使用关系的问题。
给定产品型号:
class Product extends Eloquent {
public function accessories()
{
return $this->belongsToMany('Accessory', 'product_accessory', 'product_id', 'accessory_id')
->withPivot('id')
->withTimestamps();
}
是否有任何简单的方法来确保关系方法 accessories() 使用正确的数据库连接?现在,当我执行这样的附加方法时:
$product->accessories()->attach($accessory->id, $attributes);
accessories 方法似乎指向不同于 $product 实体的另一个数据库。我相信这是因为在实例化关系时附件模型连接没有改变。
如果您看到我对您关于模型事件和观察者的原始问题的回答,这也应该从本质上解决这个问题:
所有 Eloquent 关系方法:附加、关联等...都会触发相应的模型事件,详见此处:http://laravel.com/docs/5.0/eloquent#model-events
如果您设置一个 Model Observer 来操纵使用中的连接,并 post 保存特定模型,您所有的关系调用都会自动适当地设置数据库连接。
希望对您有所帮助
-- 编辑回复评论
嗨,宇伦,
抱歉,我把您的配件电话误认为是 associate。 (保存关系)
但是,您应该能够在定义关系的地方获得类似的结果。请参阅以下示例:
class ProductModel extends Eloquent {
protected $table = 'products';
protected $connection;
protected $databases = [
'default' => 'mysql-key1',
'products' => 'mysql-key2'
];
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
public function accessories()
{
$this->connection->reconnect($this->databases['products']);
$accessories = $this->hasMany('AccessoriesModel');
$this->connection->reconnect($this->databases['default']);
return $accessories;
}
}
然后您可以通过创建一个所有受影响的模型都可以扩展的抽象 class 来更进一步,例如:
abstract class DatabaseModel extends Eloquent {
protected $connection;
protected $databases = [
'default' => 'mysql-key1',
'products' => 'mysql-key2'
];
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
protected function setProductsDatabase()
{
$this->connection->reconnect($this->databases['products']);
}
protected function resetDatabaseConnection()
{
$this->connection->reconnect($this->databases['default']);
}
}
class ProductModel extends DatabaseModel {
protected $table = 'products';
public function accessories()
{
$this->setProductsDatabase();
$accessories = $this->hasMany('AccessoriesModel');
$this->resetDatabaseConnection();
return $accessories;
}
}
这样,如果您的关系已正确配置,一切都会正常运行 "naturally",无需任何额外代码。
一个更简洁但更复杂的解决方案是,您可以触发自己的 "retrieving" 事件,而不是在模型中操作数据库,然后您可以为自定义 "retrieving" 事件 - 这是我的偏好,您可以在此处找到有关如何执行此操作的更多信息:http://laravel.io/forum/05-24-2014-how-could-i-create-custom-model-events?page=1
希望对您有所帮助
根据 Beevee 的回答,我们还可以将 Eloquent class 扩展为基础模型,以使用基于会话或基于配置的连接,例如
class BaseModel extends Eloquent {
public function __construct(array $attributes = array())
{
parent::__construct($attributes);
$this->setConnection(\DB::getDefaultConnection());
}
}
这样一来,所有的关系方法都会自动实例化以使用连接。
class Product extends BaseModel {
public function accessories()
{
return $this->belongsToMany('Accessory', 'product_accessory', 'product_id', 'accessory_id')
->withPivot('id')
->withTimestamps();
}
假设附件 class 也扩展了 BaseModel。这样就可以在运行时随意更改数据库连接了。
这又是一个跟进问题:
这一次我有关于在 eloquent 模型的多租户环境中使用关系的问题。
给定产品型号:
class Product extends Eloquent {
public function accessories()
{
return $this->belongsToMany('Accessory', 'product_accessory', 'product_id', 'accessory_id')
->withPivot('id')
->withTimestamps();
}
是否有任何简单的方法来确保关系方法 accessories() 使用正确的数据库连接?现在,当我执行这样的附加方法时:
$product->accessories()->attach($accessory->id, $attributes);
accessories 方法似乎指向不同于 $product 实体的另一个数据库。我相信这是因为在实例化关系时附件模型连接没有改变。
如果您看到我对您关于模型事件和观察者的原始问题的回答,这也应该从本质上解决这个问题:
所有 Eloquent 关系方法:附加、关联等...都会触发相应的模型事件,详见此处:http://laravel.com/docs/5.0/eloquent#model-events
如果您设置一个 Model Observer 来操纵使用中的连接,并 post 保存特定模型,您所有的关系调用都会自动适当地设置数据库连接。
希望对您有所帮助
-- 编辑回复评论
嗨,宇伦,
抱歉,我把您的配件电话误认为是 associate。 (保存关系)
但是,您应该能够在定义关系的地方获得类似的结果。请参阅以下示例:
class ProductModel extends Eloquent {
protected $table = 'products';
protected $connection;
protected $databases = [
'default' => 'mysql-key1',
'products' => 'mysql-key2'
];
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
public function accessories()
{
$this->connection->reconnect($this->databases['products']);
$accessories = $this->hasMany('AccessoriesModel');
$this->connection->reconnect($this->databases['default']);
return $accessories;
}
}
然后您可以通过创建一个所有受影响的模型都可以扩展的抽象 class 来更进一步,例如:
abstract class DatabaseModel extends Eloquent {
protected $connection;
protected $databases = [
'default' => 'mysql-key1',
'products' => 'mysql-key2'
];
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
protected function setProductsDatabase()
{
$this->connection->reconnect($this->databases['products']);
}
protected function resetDatabaseConnection()
{
$this->connection->reconnect($this->databases['default']);
}
}
class ProductModel extends DatabaseModel {
protected $table = 'products';
public function accessories()
{
$this->setProductsDatabase();
$accessories = $this->hasMany('AccessoriesModel');
$this->resetDatabaseConnection();
return $accessories;
}
}
这样,如果您的关系已正确配置,一切都会正常运行 "naturally",无需任何额外代码。
一个更简洁但更复杂的解决方案是,您可以触发自己的 "retrieving" 事件,而不是在模型中操作数据库,然后您可以为自定义 "retrieving" 事件 - 这是我的偏好,您可以在此处找到有关如何执行此操作的更多信息:http://laravel.io/forum/05-24-2014-how-could-i-create-custom-model-events?page=1
希望对您有所帮助
根据 Beevee 的回答,我们还可以将 Eloquent class 扩展为基础模型,以使用基于会话或基于配置的连接,例如
class BaseModel extends Eloquent {
public function __construct(array $attributes = array())
{
parent::__construct($attributes);
$this->setConnection(\DB::getDefaultConnection());
}
}
这样一来,所有的关系方法都会自动实例化以使用连接。
class Product extends BaseModel {
public function accessories()
{
return $this->belongsToMany('Accessory', 'product_accessory', 'product_id', 'accessory_id')
->withPivot('id')
->withTimestamps();
}
假设附件 class 也扩展了 BaseModel。这样就可以在运行时随意更改数据库连接了。