Eloquent一对一关系中hasOne应定义于哪个模型?业务场景答疑
Question 1: Registration ↔ Payment One-to-One Relationship
First off, let’s clear this up: hasOne and belongsTo are not equivalent—they define opposite sides of the relationship, and their placement directly dictates where your foreign key lives.
Relationship Direction & Foreign Key Placement
Think about the dependency here: a Payment can’t exist without a Registration (you can’t process a payment for a non-existent registration). That makes Registration the "parent" model, and Payment the "child".
- Use
hasOneon the parent model (Registration): this tells Laravel that a registration can have exactly one payment linked to it. - Use
belongsToon the child model (Payment): this confirms that each payment belongs to exactly one registration.
Foreign Key Location
The foreign key (registration_id) should only be added to the create_payments_table migration. You don’t need a foreign key in the registrations table for this relationship.
Your model code example is spot-on here:
// Registration Model class Registration extends Model { public function payment() { return $this->hasOne('App\Payment'); } } // Payment Model class Payment extends Model { public function registration() { return $this->belongsTo('App\Registration'); } }
Here’s how the payments migration should include the foreign key (simplified):
Schema::create('payments', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('registration_id'); // Add other payment fields (amount, method, status, etc.) $table->timestamps(); // Optional: cascade delete payments if their registration is removed $table->foreign('registration_id')->references('id')->on('registrations')->onDelete('cascade'); });
Question 2: Payment ↔ Reference One-to-One Relationship
Same core logic applies here, tailored to your scenario where payments can use a reference (like a voucher or promo code) stored in a separate references table.
Relationship Direction & Foreign Key Placement
A Reference is tied exclusively to one Payment (each reference is used for exactly one transaction), and a Payment can have at most one Reference (only when using that payment method).
- Use
hasOneon the parent model (Payment): this links a payment to its associated reference (if one exists). - Use
belongsToon the child model (Reference): this confirms the reference belongs to a single payment.
Foreign Key Location
The foreign key (payment_id) should be added to the create_references_table migration. No foreign key is needed in the payments table for this relationship.
Your model code here is also correct:
// Payment Model class Payment extends Model { public function registration() { return $this->belongsTo('App\Registration'); } public function reference() { return $this->hasOne('App\Reference'); } } // Reference Model class Reference extends Model { public function payment() { return $this->belongsTo('App\Payment'); } }
And the references migration with the foreign key:
Schema::create('references', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('payment_id'); // Add other reference fields (code, value, expiry date, etc.) $table->timestamps(); $table->foreign('payment_id')->references('id')->on('payments')->onDelete('cascade'); });
Quick Rule of Thumb for Laravel One-to-One Relationships
- If Model A has one Model B → Model B belongs to Model A.
- The foreign key always lives in the table of the model that uses
belongsTo.
内容的提问来源于stack exchange,提问作者johnW

