【问题标题】:Laravel whereHas across two separate databasesLaravel whereHas 跨两个独立的数据库
【发布时间】:2015-02-08 06:34:10
【问题描述】:

问题:我只想在客户已经下订单的情况下获得当年的客户。客户和订单位于两个单独的数据库中(这不能更改)。这些关系都已设置并正常工作,但是当我尝试以下操作时,我不断收到 SQL 错误,因为它试图在“客户”数据库中搜索“订单”。在这种情况下是否有强制 Laravel 使用正确的数据库?

$customers = $customers->whereHas('orders', function($query){
    $query->where('academic_year_id', '=', $this->current_academic_year->id);
});

$customers = $customers->orderBy('DFKEY','ASC')->get();

订购型号:

public function customer()
{
    return $this->belongsTo('Customer','dfkey');
}

客户模型:

protected $connection = 'mysql2';

public function orders()
{
    return $this->hasMany('Order','dfkey','DFKEY');
}

提前致谢!

【问题讨论】:

  • 听起来关系有问题,orders 是不是与客户的 belongsToMany 关系?您需要 Customer 模型中的 orders 函数,另外我认为您需要最后的 get 语句才能实际返回结果
  • 感谢您的回复,我已经更详细地更新了我原来的问题...
  • 对不起,我误读了您的问题,而不是两个单独的数据库,我出于某种原因读取了两个单独的表,我责怪睡眠
  • 如果您还没有找到解决该问题的方法,但似乎在客户模型中将数据库名称添加到表名称之前似乎可以解决问题:stackoverflow.com/questions/23457561/…

标签: php laravel laravel-4 eloquent relationship


【解决方案1】:

这其实是一个非常好的问题! 直接在该模型上进行简单查询不会有问题,因为 Laravel 使用模型的默认连接,但是如果您在另一个数据库中有相关模型并且执行一些高级查询,例如:whereHas('relationName'),Laravel 将使用该连接将导致关于不存在列的 SQL 错误(因为它在错误的数据库中查找)。

这是解决这个问题的最佳方案:

在您的相关模型中创建这样的构造函数:

public function __construct(array $attributes = [])
{
    $this->table = 'db_name.'.$this->table;
    parent::__construct();
}

【讨论】:

    【解决方案2】:

    包 hoyvoy/laravel-cross-database-subqueries 允许您对同一服务器中的数据库执行此操作。您还需要指定 Agus Trombotto 指定的所有数据库连接和与其相关的模型。最后,引用另一个数据库的模型必须从 Hoyvoy\CrossDatabase\Eloquent\Model 而不是 Illuminate\Database\Eloquent\Model 扩展。

    【讨论】:

      【解决方案3】:

      聚会迟到了,但对于遇到类似问题的其他人来说,以下应该可以工作(只要两个数据库都在一个服务器上)。

      明确设置连接和表。

      protected $connection = 'mysql2';
      protected $table_name = 'mysql2.orders';
      

      或者,如果您愿意 - 像这样动态设置表格:

      protected $table = 'orders';
      public function __construct() {
          $this->table = DB::connection($this->connection)->getDatabaseName() . '.' . $this->table_name;
      }
      

      甚至

      public function __construct() {
          $this->table = DB::connection($this->connection)->getDatabaseName() . '.' . $this->getTable();
      }
      

      【讨论】:

      • 谢谢你,但在你的第一个块的 $table_name 中,是连接名还是数据库名?
      【解决方案4】:

      Unfurtanelly 没有直接的方法,但你可以分两步完成,这和 Laravel 正常的做法是一样的。

      它简单、干净、有效,而且你不会弄乱可能在更新时改变的核心 Laravel 功能

          $orders = Order::where('academic_year_id', $this->current_academic_year->id)
                           ->select('id')
                           ->pluck('id');
      
      
          $customers = $customers->whereIn('order_id', $orders)
                                 ->orderBy('DFKEY','ASC')
                                 ->get();
      

      希望这对你有用。

      P.D.:你可以在 where 中跳过等号

      【讨论】:

        【解决方案5】:

        我已经通过添加“连接”和“表”变量模型来解决这个问题,这些模型指定了保存模型的数据库。

        例如,我在用户表中名为“core_database”的数据库中有一个名为“用户”的模型。 另一方面,我在表“user_events”中名为“logs_database”的数据库中有一个名为“UserEvents”的模型

        所以我将在 config/database.php 文件上有两个连接:

        'core_db_connection' => [
                'driver' => 'mysql',
                'host' => host_ip,
                'port' => port,
                'database' => 'core_database',
                'username' => username,
                'password' => password,
                ....
            ],
        
        'logs_db_connection' => [
                'driver' => 'mysql',
                'host' => host_ip,
                'port' => port,
                'database' => 'logs_database',
                'username' => username,
                'password' => password,
                ....
            ],
        

        模型会是这样的:

        class User extends Authenticatable {
          protected $table = 'core_database.users';
          protected $connection = 'core_db_connection';
          ...
        }
        
        class UserEvents extends Model {
          protected $table = 'logs_database.user_events';
          protected $connection = 'logs_db_connection';
          ...
        }
        

        这是在同一数据库服务器中的数据库中测试的。 数据库连接具有相同的主机 ip。 我没有尝试过其他方式

        使用此配置,我可以在同一数据库服务器(在我的例子中为 RDS)中的两个或多个独立数据库中进行任何查询。

        希望对你有帮助!

        【讨论】:

        • 这将不允许 whereHas 正常运行,您将收到 SQL 错误,因为 whereHas 不支持跨数据库关系
        【解决方案6】:

        使用过滤器解决了这个问题:

        public function index()
        {   
            $customers = new Customer;
            // Make sure customers are current parents of students
            $customers = $customers->whereHas('students', function($q) {
                $q->where('STATUS', '=', 'FULL');
            });
        
            //Filter results
            if(Input::get('academic_year') == 'ordered'){
                $customers = $customers->orderBy('DFKEY','ASC')->get();
                $filtered = $customers->filter(function($customer)
                {
                    if ($customer->orders()->where('academic_year_id','=',$this->current_academic_year->id)->first()) {
                        return true;
                    }
                });
                $customers = $filtered;
                return View::make('admin.customers.index',compact('customers'));
            }
        
            $customers = $customers->orderBy('DFKEY','ASC')->get();
        
            return View::make('admin.customers.index',compact('customers'));
        }
        

        【讨论】:

          【解决方案7】:

          尝试像这样编写查询并按原样放置您的数据库和表名->

          $customers = Schema::connection('your_database_name')::table('respective_table_name')
          ->where('academic_year_id', '=', $this->current_academic_year->id)
          ->orderBy('DFKEY','ASC')
          ->get();
          

          【讨论】:

          • 请告诉我订单和客户表的表结构是什么,我想知道你是如何保存数据的。所以我可以澄清更多。首先,你必须从哪个表中获取什么,然后更改数据库并运行第二个查询以获取姓名、电子邮件、电话号码等游标信息。
          猜你喜欢
          • 2022-01-22
          • 2021-07-19
          • 1970-01-01
          • 2011-06-08
          • 1970-01-01
          • 1970-01-01
          • 2023-03-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多