【问题标题】:Laravel:通过“有多个”关系订购模型
【发布时间】:2022-01-21 23:23:27
【问题描述】:

我有一个有很多联系人的客户模型。我使用 Laravel 8 中的“Has One Of Many”关系定义了一个关系以获取客户的最新联系:

模型

class Customer extends Model
{
    use HasFactory;

    public function contacts() 
    {
        return $this->hasMany(Contact::class);
    }

    public function latestContact()
    {
        return $this->hasOne(Contact::class)->ofMany('contacted_at', 'max')->withDefault();
    }
}

class Contact extends Model
{
    use HasFactory;

    protected $casts = [
        'contacted_at' => 'datetime',
    ];

    public function customer()
    {
        return $this->belongsTo(Customer::class);
    }
}

迁移(联系模型)

class CreateContactsTable extends Migration
{
    public function up()
    {
        Schema::create('contacts', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
            $table->softDeletes();

            $table->foreignID('customer_id');
            $table->string('type');
            $table->dateTime('contacted_at');
        });
    }
}

在我看来,我想显示所有客户并按他们的最新联系人订购他们。但是,我不知道该怎么做。

我尝试通过 join 方法来实现它,但显然每个客户都有不同的条目。

$query = Customer::select('customers.*', 'contacts.contacted_at as contacted_at')
    ->join('contacts', 'customers.id', '=', 'contacts.customer_id')
    ->orderby('contacts.contacted_at')
    ->with('latestContact')

了解 Laravel 一定是实现这一目标的好方法或帮手。有什么想法吗?

【问题讨论】:

  • 你的数据库中有时间戳吗?
  • 是的,我愿意。但就我而言,“contacted_at”列是获取最新联系人的重要列。更新了我的帖子以正确反映它。
  • @maxiw46 你能发布你的完整模型吗?
  • 那么你的目标是什么?显示按最新联系人排序的所有联系人?或者您只想显示几个最近的联系人?
  • 你为什么不那样做? Custumer::with('contacts')->get()->orderBy('contacted_at'); 在可以订购 cotacts 时,定义最新联系人的新方法的原因是什么?

标签: php laravel eloquent


【解决方案1】:

我认为最简洁的方法是使用子查询连接:

$latestContacts = Contact::select('customer_id',DB::raw('max(contacted_at) as latest_contact'))->groupBy('customer_id');

$query = Customer::select('customers.*', 'latest_contacts.latest_contact')
         ->joinSub($latestContacts, 'latest_contacts', function ($join){
            $join->on([['customer.id', 'latest_contacts.customer_id']]);
        })
        ->orderBy('latest_contacts.latest_contact')
        ->get();

更多信息:https://laravel.com/docs/8.x/queries#subquery-joins

【讨论】:

  • 效果很好!非常感谢!只有一个小评论:$join->on() 中的'customer.id' 缺少一个's'。它应该是“customers.id”。我希望这在 Laravel 中看起来更干净 :-) 但无论如何...再次非常感谢。
  • 更正:我刚刚注意到现在只显示至少有联系的客户。但是,我也想向没有任何联系的客户展示。因此,我认为它应该改为 ->leftJoinSub 而不是 ->joinSub。
  • 是的,您可以改用 leftJoinSub。很高兴为您提供帮助。
【解决方案2】:

我怀疑你的迁移有问题,外键约束是这样定义的:

查看文档: https://laravel.com/docs/8.x/migrations#foreign-key-constraints

方法一:定义外键约束

public function up()
{        
    Schema::create('contacts', function (Blueprint $table) {
        $table->id();            
        $table->foreignId('consumer_id')->constrained();          
                    
        $table->string('type');
        $table->dateTime('contacted_at');
        $table->timestamps();
        $table->softDeletes();
    });    
}

方法二:定义外键约束

public function up()
{        
    Schema::create('contacts', function (Blueprint $table) {
        $table->id();                        
        $table->unsignedBigInteger('customer_id');                        
        $table->foreign('customer_id')->references('id')->on('customers');
                    
        $table->string('type');
        $table->dateTime('contacted_at');
        $table->timestamps();
        $table->softDeletes();
    });    
}

【讨论】:

  • 在 Laravel 8 中,foreignID() 助手创建了一个 UNSIGNED BIGINT 等效列。迁移没有问题。
  • @maxiw46 foreignID() 是错字,应该是 foreignId()。为了您的方便,我会更新答案。
  • 是的。尽管如此,迁移工作正常。我的问题是关于通过关系对客户模型进行排序。迁移没有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-02
  • 1970-01-01
  • 1970-01-01
  • 2017-07-05
相关资源
最近更新 更多