现在我在与模型A相同的数据库中有一个名为a_bs的pivot_table.
我在模型A中设置了这样的belongsToMany relatinoship
public function bs() { return $this->belongsToMany('B','a_bs','a_id','b_id'); }
当我尝试访问这种关系时:
$a = A::find($id); print_r($a->bs->lists('id'));
我得到一个错误,我的数据透视表在模型B的数据库中不存在.这显然是正确的,因为数据透视表位于模型A的数据库中.我怎么能让Laravel知道呢?
不建议将数据透视表放在模型B的数据库中
public function bs() { $database = $this->getConnection()->getDatabaseName(); return $this->belongsToMany('B',"$database.a_bs",'b_id'); }
我正在动态获取数据库名称,因为我的连接是基于环境变量配置的. Laravel似乎假设数据透视表存在于与目标关系相同的数据库中,因此这将强制它查找与此方法所在的模型相对应的数据库,即“A”域.
如果您不担心sqlite数据库,即在单元测试范围内,那就是您所需要的.但如果你是,继续阅读.
首先,前面的例子本身并不充分. $database的值最终将成为文件路径,因此您需要将其别名为不会破坏sql语句的内容,并使其可供当前连接访问. “ATTACH DATABASE’$database’AS $name”就是这样做的:
public function bs() { $database = $this->getConnection()->getDatabaseName(); if (is_file($database)) { $connection = app('B')->getConnection()->getName(); $name = $this->getConnection()->getName(); \Illuminate\Support\Facades\DB::connection($connection)->statement("ATTACH DATABASE '$database' AS $name"); $database = $name; } return $this->belongsToMany('B','b_id'); }
警告:事务搞砸了:如果当前连接正在使用事务,则ATTACH DATABASE语句将失败.您可以在执行该语句后对其使用事务.如果相关连接使用事务,则结果数据将以静默方式呈现为当前数据不可见.这让我疯狂的时间超过了我想要承认的时间,因为我的查询运行没有错误,但一直空着.似乎只有真正写入附加数据库的数据实际上可以被附加到的数据库访问.
因此,在被强制写入附加数据库之后,您可能仍希望自己的测试得到清理.一个简单的解决方案就是使用$this-> artisan(‘migrate:rollback’,[‘ – database’=> $attachedConnectionName]);.但是如果你有多个需要相同表的测试,这不是很有效,因为它迫使他们每次都必须重建它们.
更好的选择是截断表格,但保留其结构:
//Get all tables within the attached database collect(DB::connection($database)->select("SELECT name FROM sqlite_master WHERE type = 'table'"))->each(function ($table) use ($name) { //Clear all entries for the table DB::connection($database)->delete("DELETE FROM '$table->name'"); //Reset any auto-incremented index value DB::connection($database)->delete("DELETE FROM sqlite_sequence WHERE name = '$table->name'"); }); }
这将擦除该连接中的所有数据,但是没有理由不能将某种类型的过滤器应用于您认为合适的过滤器.或者,您可以利用sqlite DB是易于访问的文件,只需将附加的文件复制到临时文件,并在测试完成后使用它覆盖源.结果在功能上与交易相同.