laravel ORM如何在视图中访问hasOne相关表

时间:2014-10-22 20:13:44

标签: laravel-4 eloquent

我知道这似乎是一个简单的问题,但在查看了官方文档和2个教程后,我不清楚。有没有使用foreign_keys的冲突示例,以及在不同的位置使用类Model:all()以及与hasMany关系一起使用...这样做似乎很简单我很沮丧我无法轻易找到答案。我知道答案可能是有人,但有几个部分对于初学者来说并不明显,因为到处都有相互矛盾的例子,我甚至发现一些不起作用的命令(经其他帖子验证),但仍然有记录。那么请有人为我澄清这个简单的问题,这样事情就会变得不那么混乱了。

如何在我的视图中访问相关表格?我收到错误“试图获取非对象的属性(视图:”当我在我的视图中运行它

@foreach $programs as $program
     {{{$program->program_segment->name}}}
@endforeach

程序是用于显示非相关数据的模型。 program_segment是我的程序模型中定义的函数,它与我想要访问的相关表具有has_One关系。

相关文件:

Model:  
class ProgramEvent extends Eloquent {

        protected $table = 'program_events';
        public $timestamps = true;

        public function program_segment()
        {
            return $this->hasOne('ProgramSegment');
        }
}
class ProgramSegment extends Eloquent {

    protected $table = 'program_segments';
    public $timestamps = true;

}


Migrations:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateProgramEventsTable extends Migration {

    public function up()
    {
        Schema::create('program_events', function(Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
            $table->string('name', 32);
            $table->date('date');
            $table->time('start_time');
            $table->time('end_time');
            $table->string('location', 32);
        });
    }

    public function down()
    {
        Schema::drop('program_events');
    }
}

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateProgramSegmentsTable extends Migration {

    public function up()
    {
        Schema::create('program_segments', function(Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
            $table->string('name', 32);
            $table->text('description');
            $table->decimal('cost', 3,2);
            $table->integer('program_event_id')->unsigned()->nullable();
            $table->foreign('program_event_id')->references('id')->on('program_events')->onDelete('cascade');

        });
    }

    public function down()
    {
        Schema::drop('program_segments');
    }
}

Controller:
    public function index()
    {
        $programs = ProgramEvent::with('program_segment')->get();
        return View::make('programs.index', compact('programs'));

    }

2 个答案:

答案 0 :(得分:1)

在查询模型时,您似乎需要加载关系。您可以使用"加载"加载它们。操作者:

控制器:

public function index()
{
    $programs = ProgramEvent::with('program_segment')->get();
    return View::make('programs.index', compact('programs'));
}

<强> UPD: 此外,直接指定用于关联表的列总是一个好主意。这里的文档说明了什么:

return $this->hasOne('Model', 'foreign_key', 'local_key');

另外,我认为你缺少program_segmet中用于保存父ID(program_event_id)的列。添加它可以很好地制作外键,但不是必需的。

答案 1 :(得分:1)

问题的根源在于缺少外键。 总是需要关系中的外键,否则您的数据库无法将一条记录连接到另一条记录。如果没有外键,ORM无法知道哪些数据是相关的。

如果您的外键被命名为遵循惯例model_id,其中model是您定义关系的模型的名称,那么您不需要指定 hasOne语句中的外键名称...但外键仍然必须存在在数据库中。因此,如果您的外键名为program_event_id,则您的hasOne语句将按原样运行。 (在第二条错误消息中,您可以看到它期望列program_event_id。)但是,如果您将外键命名为其他内容,则应将其添加到hasOne定义中,即{ {1}});&#39;

在迁移中添加外键需要两个语句(按此顺序):

return $this->hasOne('ProgramSegment', 'my_foreign_key

(在第一行末尾添加$table->integer('program_event_id')->unsigned(); $table->foreign('program_event_id')->references('id')->on('progam_events'); 不是必需的,但是->index()是。)


除此之外,您的一些错误可能是由您姓名中的拼写错误引起的。您的原始&#39;非对象&#39;可能是因为您的控制器正在将unsigned()传递给您的视图而导致错误,但在您的视图中,您引用了'programs'。就您的观点而言,$program->program_segment->name存在,但$programs不存在。

您的外键约束错误也可能由拼写错误引起,因为您将表定义为$program;如果这是故意的,那么迁移中的外键定义也必须引用progam_events而不是progam_events


正确设置外键后,使用program_events运算符 必要才能访问您的关系 - 您可以按照自己的方式获取相关模型最初做的是with。但是,如果您计划循环遍历$program->program_segment->name的结果集并显示每个相关的$program,那么这是一种很好的做法。使用program_segment->name将仅使用2个查询带来所有相关记录,因此您不需要对每个相关记录进行1次查询。这避免了称为&#34; N + 1&#34;问题,并使您的查询更有效。


最后,所有这些都可能是不必要的......如果你的关系真正的是一对一的关系(所以只有一个事件只有一个段),你可以,大多数情况下在这种情况下,只需将两个表组合在一起即可完全消除::with关系。在某些情况下,将一对一数据分成两个表是有意义的,但这些与性能有关,而不是数据结构。但我怀疑,你的两个表之间的关系应该是一对多的关系。


在正确设置关系后,请确保在hasOne循环中添加一项检查,以确保在您尝试访问之前,某个foreach存在program_segment它;否则,如果您点击了一个没有相关program_segment的程序,您最终会得到一个&#34;尝试获取非对象的属性&#34;错误:

program_event