Laravel中跨多个数据库的归属关系

我有型号A和型号B,它们位于两个不同的数据库中

现在我有一个pivot_表,名为a_bs,与modela位于同一数据库中

我在型号A

公共功能bs()
{
返回$this->belongTomany(’B’,’a_-bs’,’a_-id’,’B_-id’);
}

当我尝试这样访问此关系时:

$a=a::find($id);
打印($a->bs->列表('id'));

我得到一个错误,我的数据透视表在模型B的数据库中不存在。这显然是正确的,因为透视表位于模型A的数据库中。我怎么能让拉威尔知道

不建议将数据透视表放入型号B的数据库中

非常简单:

公共功能bs()
{
$database=$this->getConnection()->getDatabaseName();
返回$this->belongTomany(’B’,’$database.a_-bs’,’a_-id’,’B_-id’);
}

我正在动态获取数据库名称,因为我的连接是基于环境变量配置的。Laravel似乎假设pivot表与目标关系存在于同一数据库中,因此这将迫使它转而查找与此方法所在的模型对应的数据库,即您的“A”域


如果您不担心SQLite数据库,即在单元测试范围内,那么这就是您所需要的。但如果是,请继续阅读。


首先,前面的例子本身是不够的。$database的值最终将成为一个文件路径,因此您需要将其别名为不会破坏SQL语句的内容,并使其可供当前连接访问“将数据库“$DATABASE”附加为$name”就是这样做的:

公共功能bs()
{
$database=$this->getConnection()->getDatabaseName();
if(is_文件($database)){
$connection=app(’B’)->getConnection()->getName();
$name=$this->getConnection()->getName();
\illumb\Support\Facades\DB::connection($connection)>语句(“将数据库“$DATABASE”附加为$name”);
$database=$name;
}
返回$this->belongTomany(’B’,’$database.a_-bs’,’a_-id’,’B_-id’);
}

警告:事务会弄糟这一点:如果当前连接正在使用事务,则ATTACH DATABASE语句将失败。但是,在执行该语句之后,就可以使用它上的事务

然而,如果相关的连接使用事务,则生成的数据将对当前数据不可见。这让我发疯的时间比我愿意承认的要长,因为我的查询没有出错,但总是空出来。似乎只有真正写入附加数据库的数据才能被附加数据库访问

因此,在被迫写入连接的数据库后,您可能仍然希望测试在完成后进行清理。一个简单的解决方案就是使用$this->artisan('migrate:rollback',['--database'=>$attachedConnectionName])。但是,如果您有多个测试需要相同的表,那么这不是非常有效,因为它迫使它们每次都必须重新构建它们

更好的选择是截断表,但保留其结构:

//获取附加数据库中的所有表
collect(DB::connection($database)->select(“从sqlite_master中选择名称,其中类型='table'))->;每个(函数($table)使用($name){
//清除表的所有条目
数据库::连接($database)>删除(“从“$table->name”中删除”);
//重置任何自动递增的索引值
DB::connection($database)>delete(“从sqlite_序列中删除,其中name='$table->name');
});
}

这将擦除该连接中的所有数据,但您没有理由不能对该连接应用某种类型的过滤器,不管您认为合适与否。或者,您可以利用SQLite DBs是易于访问的文件这一事实,只需将附加的文件复制到临时文件,并在测试完成后使用它覆盖源文件。结果在功能上与事务相同

发表评论