【问题标题】:Laravel Eloquent related model must match two foreign keysLaravel Eloquent 相关模型必须匹配两个外键
【发布时间】:2018-04-27 00:28:43
【问题描述】:

我在 laravel 框架中使用 eloquent。我想通过表 B 和表 C 从表 D 中获取与表 A 相关的模型。

有没有办法做到这一点?

这是数据库中的情况:

这是数据库的示例数据:

INSERT INTO A (idA) VALUES(1);
INSERT INTO A (idA) VALUES(2);
INSERT INTO A (idA) VALUES(3);

INSERT INTO B (idB, A_idA) VALUES(1, 1);
INSERT INTO B (idB, A_idA) VALUES(2, 2);

INSERT INTO C (idC, A_idA) VALUES(1, 1);
INSERT INTO C (idC, A_idA) VALUES(2, 2);
INSERT INTO C (idC, A_idA) VALUES(3, 3);

INSERT INTO D (idD, B_idB, C_idC) VALUES(1, 1, 1);
INSERT INTO D (idD, B_idB, C_idC) VALUES(2, 2, 2);
INSERT INTO D (idD, B_idB, C_idC) VALUES(3, 2, 3);

以下是模型:

class A extends Model
{
    protected $table = "A";
    protected $primaryKey = "idA";
    public $timestamps = false;

    public function B()
    {
        return $this->hasMany("App\B", "A_idA");
    }

    public function C()
    {
        return $this->hasMany("App\C", "A_idA");
    }
}

class B extends Model
{
    protected $table = "B";
    protected $primaryKey = "idB";
    public $timestamps = false;

    public function D()
    {
        return $this->hasMany("App\D", "B_idB");
    }

    public function A()
    {
        return $this->belongsTo("App\A", "A_idA");
    }
}

class C extends Model
{
    protected $table = "C";
    protected $primaryKey = "idC";
    public $timestamps = false;

    public function D()
    {
        return $this->hasMany("App\D", "C_idC");
    }

    public function A()
    {
        return $this->belongsTo("App\A", "A_idA");
    }
}

class D extends Model
{
    protected $table = "D";
    protected $primaryKey = "idD";
    public $timestamps = false;

    public function B()
    {
        return $this->belongsTo("App\B", "B_idB");
    }

    public function C()
    {
        return $this->belongsTo("App\C", "C_idC");
    }
}

这里是控制器

class TestController extends Controller
{
    public function test()
    {
        $aWithRelatedDs = A::with(['B.D'])->whereHas("B.D")->whereHas("C.D")->get();
        dd($aWithRelatedDs);
    }
}

这是输出:

Collection {#380 ▼
  #items: array:2 [▼
    0 => A {#390 ▶}
    1 => A {#388 ▼
      #table: "A"
      ... snip ...
      #relations: array:1 [▼
        "B" => Collection {#387 ▼
          #items: array:1 [▼
            0 => B {#398 ▼
              #table: "B"
              ... snip ...
              #relations: array:1 [▼
                "D" => Collection {#395 ▼
                  #items: array:2 [▼
                    0 => D {#407 ▼
                      #table: "D"
                      ... snip ...
                      #attributes: array:3 [▼
                        "idD" => 2
                        "B_idB" => 2
                        "C_idC" => 2
                      ]
                      ... snip ...
                    }
                    1 => D {#408 ▼
                      #table: "D"
                      ... snip ...
                      #attributes: array:3 [▼
                        "idD" => 3
                        "B_idB" => 2
                        "C_idC" => 3
                      ]
                      ... snip ...
                    }]}]
... snip ...

问题:A #2 没有通过 B 和 C 关联的两个 D,它只有通过两个中间表关联的 D #2,但在上面的结果中它仍然被列出。我该如何限制这一点,所以两个关联必须是同一个模型?

【问题讨论】:

  • 请发布您已经尝试过的代码。
  • 两个 whereHas 是正确的方法。你做错了
  • @Namoshek 我添加了代码。谢谢。
  • @devk 一定是我看不到的东西。
  • 哦,它们必须关联到同一个模型 D。这会改变它。我不确定 2 whereHas 是要走的路。像A::whereHas('b.d.c')->get() 这样的东西怎么样。注意到我不确定点符号是否适用于whereHas,只是假设它在您的示例中有效

标签: php laravel eloquent


【解决方案1】:

如果您想获取所有A 至少有一个D 通过BB 连接到AC,那么原始SQL 查询将如下所示:

SELECT *
FROM A
WHERE EXISTS (
  SELECT D.id
  FROM D
    INNER JOIN B ON D.b_id = B.id
    INNER JOIN C ON D.c_id = C.id
  WHERE B.a_id = A.id
    AND C.a_id = A.id
)

为此我还准备了SQL Fiddle

我的建议是在A 上创建一个新关系,它可以找到所有DB,为此我们找到一个C,它也连接回A。听起来很奇怪,但很简单,看起来像这样:

public function doubleLinkedDs(): HasManyThrough
{
    return $this->hasManyThrough(D::class, B::class)
        ->whereHas('C', function ($q) {
            $q->where('a_id', $this->id);
        });
}

顺便说一句,这需要您建立适当的关系。但据我从问题中可以看出,这应该没问题。

如果我们定义了关系,我们应该能够执行以下非常简单的查询:

A::has('doubleLinkedDs')
    ->with('doubleLinkedDs')
    ->get();

【讨论】:

    猜你喜欢
    • 2013-11-22
    • 2017-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-16
    • 2013-06-10
    • 2014-11-25
    相关资源
    最近更新 更多