在与现有记录的morphOne()关系上调用save()会创建一个新记录而不删除旧记录

时间:2015-12-03 22:46:33

标签: laravel eloquent laravel-5.1

如果你有一个模型,那就说一个Post模型,与morphOne()模型有Image的关系。您$post->image()->save()第二次在images表中为同一Post创建了两个条目。由于它是一对一的关系,似乎不应该发生这种情况。 $post->image继续提及保存的第一个。

associate()方法也无济于事。您只能使用Image属性在morphTo上调用它 - 它会更新帖子ID,但仍然不会影响第一个Image已保存的内容。

这是一个错误吗?我应该在Laravel Github上存档吗?有没有办法解决这个问题 - 我只需要手动删除现有的吗? Someone else also made a note of this 6 months ago,我很惊讶现在还没有解决这个问题。

4 个答案:

答案 0 :(得分:2)

您似乎不应该致电$post->image()->save()而是$post->image->save()。您正在调用保存关系的保存,这将保存一个新关系。你应该在实际的图像对象上调用save。

编辑:阅读Brynn对该解决方案的回应,MorphOne是一个变幻无常的野兽

答案 1 :(得分:1)

我的想法中存在的缺陷是,雄辩的关系在某种程度上是一份具有约束力的合同 - 他们并非如此。正如@Jeff指出的那样,hasOnehasMany之间唯一真正的区别在于hasOne为您调用->first()而不是->get()。 Laravel要求你真正维持这些关系。

这意味着即使您在morphOnehasOne之间存在PostImage关系(帖子只能有一张图片,而图片只能属于对于一个帖子,你可以打电话给$post->save($image),直到奶牛回家,Laravel会愉快地在images表中创建无限条目,所有条目都列出与{34}父母相同的Post ID&#34 ;.它不会自动删除或分离前一个。同样,您可以associate()将无限制的现有图像发送到单个帖子。调用$post->image只会返回与之关联的第一张图片,这对我的第一段是有意义的。

first reply on this Laravel issue讨论了这个问题:

  

这个想法似乎是Laravel应该只是编辑模型   开发人员正在调用的关系的一面

据我所知,这意味着在您更新images对象时,不会更新Post表格以删除或取消现有图片。

我认为我的困惑源于试图将用户上传新图像的想法转换为必须在Laravel中创建新Image对象的逻辑。实际上我应该更新或使用新图像创建Post的图像。如果它已经有图像对象,只需更新它。它不需要是一个新的Image对象。或者,如果由于某种原因需要存储现有图像,只需将其与Post分离,然后再添加一个。由于我没有处理维持一对一的关系,因此必须手动完成,如果这是我的应用程序所需的逻辑。

答案 2 :(得分:0)

  

实际上,我应该更新或创建

我认为这是最理想的解决方案:使用updateOrCreate()函数。第一个参数是用于查找现有模型的属性数组。第二个是您要更新/添加的属性。如果您不关心任何的属性被覆盖(例如在一个非常简单的模型中),则为第一个参数传递一个空数组将简单地更新现有的关系(如果有)。这是紧凑而干净的,并且可能是单线的。

$attributesIWantToSave = [
    // ...
];
$post->image()->updateOrCreate([], $attributesIWantToSave);

答案 3 :(得分:0)

这是特质和职业。在模型中使用特征。您需要将其适合您自己的命名间隔方案。

use MorphExactlyOne as Relation;
trait MorphOne{

    public function morphOne($related, $name, $type = null, $id = null, $localKey = null){
        $instance = $this->newRelatedInstance($related);

        [$type, $id] = $this->getMorphs($name, $type, $id);

        $table = $instance->getTable();

        $localKey = $localKey ?:$this->getKeyName();

        return new Relation($instance->newQuery(), $this, $table . '.' . $type, $table . '.' . $id, $localKey);
    }
}
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphOne as BaseRelationship;

class MorphExactlyOne extends BaseRelationship{

    public function save(Model $has_morphTo_relationship){
        if($has_morphTo_relationship = parent::save($has_morphTo_relationship)
            and $has_morphTo_relationship->wasRecentlyCreated){

            $type       = $this->morphClass;
            $type_field = explode('.', $this->morphType);
            $type_field = end($type_field);

            $key       = $this->parent->getKey();
            $key_field = explode('.', $this->foreignKey);
            $key_field = end($key_field);

            $builder = get_class($has_morphTo_relationship);
            $builder::where($key_field, $key)
                    ->where($type_field, $type)
                    ->where($has_morphTo_relationship->getKeyName(), '!=', $has_morphTo_relationship->getKey())
                    ->delete();
        }

    return $has_morphTo_relationship;
    }
}

相关问题