Laravel Eloquent 关系与多个带有“OR”的外键
Posted
技术标签:
【中文标题】Laravel Eloquent 关系与多个带有“OR”的外键【英文标题】:Laravel Eloquent relations with multiple foreign key with "OR" 【发布时间】:2021-04-09 02:03:09 【问题描述】:我有模型Account
,账户有交易-模型Transactions
。
在 Transactions
我有两个外键 - from_account_id
和 to_account_id
都与 Account
模型相关。
现在我想在这两个模型之间创建关系(例如... WHERE transactions.from_account_id = accounts.id OR transactions.to_account_id = accounts.id
),但 Eloquent 不支持关系上的两个外键。
我找到了topclaudy/compoships这个包,但是不支持OR
有什么解决办法吗?
【问题讨论】:
【参考方案1】:在两个外键上定义关系从逻辑上讲是没有意义的。在您的用例中,逻辑关系将是
class Account extends Model
public function outwardTransactions()
return $this->hasMany(Transaction::class, 'from_account_id');
public function inwardTransactions()
return $this->hasMany(Transaction::class, 'to_account_id');
public function allTransactions()
return $this->outwardTransactions->concat($this->inwardTransactions);
//Or a local scope on model to get all transactions
public function scopeWithAllTransactions($query)
return $query->with(['outwardTransactions', 'inwardTransactions']);
Transaction 模型上的关系可以定义为
class Transaction extends Model
public function sourceAccount()
return $this->belongsTo(Account::class, 'from_account_id', 'id');
public function destinationAccount()
return $this->belongsTo(Account::class, 'to_account_id', 'id');
public function accounts()
return collect([$this->sourceAccount, $this->destinationAccount]);
//Or a local scope on model to get all accounts
public function scopeWithAllAccounts($query)
return $query->with(['sourceAccount', 'destinationAccount']);
多对多关系
为了接近您想要实现的目标,一种方法是使用 Account 和 Transaction 模型之间的多对多关系,因为在逻辑上
一笔交易有很多账户(每笔交易有两个账户) 一个账户(可以有)hasMany Transaction(s)会有一个中间链接表account_transaction
,上面会有一个额外的列type
,可以包含credit或debit作为值。
//account_transaction table
public function up()
Schema::create('account_transaction', function (Blueprint $table)
$table->id();
$table->foreignId('account_id')->constrained();
$table->foreignId('transaction_id')->constrained;
$table->enum('type', ['debit', 'credit']);
$table->timestamps();
$table->unique(['account_id', 'transaction_id']);
);
//transactions table
public function up()
Schema::create('transactions', function (Blueprint $table)
$table->id();
$table->unsignedInteger('amount');
//any other columns...
$table->timestamps();
);
那么关系可以定义为
class Account extends Model
public function transactions()
return $this->belongsToMany(Transaction::class)
->withPivot('type')
->withTimestamps();
//... rest of the class code
class Transaction extends Model
public function accounts()
return $this->belongsToMany(Account::class)
->withPivot('type')
->withTimestamps();
//... rest of the class code
唯一的问题是,在为交易创建条目时,您需要在 account_transaction
表中创建两个对应的条目 - 一个用于具有 debit 类型的 from_account
,另一个用于to_account
带有 credit 类型
//Example transaction:
//FromAccountId = 5
//ToAccountId = 20
//Amount = $100
$transaction = Transaction::create(['amount' => 10000]); //100$ x 100 = 10000 cents in database
$transaction->accounts()->attach([
5 => ['type' => 'debit'],
20 => ['type' => 'credit'],
]);
然后您可以根据需要执行各种查询,也可以查询关系存在has
,whereHas
$creditTransactions = $account->transactions()->wherePivot('type', 'credit')->get();
$currentDayTransactions = $account->transactions()->whereDate('created_at', now())->get();
【讨论】:
你的例子很好,除非你不打算使用 whereHas :)) @LevanTetemadze 从逻辑上讲,Account 和 Transaction 模型之间的关系应该是Many-to-Many
- 已更新答案以上是关于Laravel Eloquent 关系与多个带有“OR”的外键的主要内容,如果未能解决你的问题,请参考以下文章
Laravel/Eloquent - 创建与可能具有或不具有属性的父模型相关的多个子模型的关系
如何使用 Laravel 的 Eloquent 关系与 Eager Loading 连接 3 个表?