如果你有一个模型,那就说一个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,我很惊讶现在还没有解决这个问题。
答案 0 :(得分:2)
您似乎不应该致电$post->image()->save()
而是$post->image->save()
。您正在调用保存关系的保存,这将保存一个新关系。你应该在实际的图像对象上调用save。
编辑:阅读Brynn对该解决方案的回应,MorphOne是一个变幻无常的野兽
答案 1 :(得分:1)
我的想法中存在的缺陷是,雄辩的关系在某种程度上是一份具有约束力的合同 - 他们并非如此。正如@Jeff指出的那样,hasOne
和hasMany
之间唯一真正的区别在于hasOne
为您调用->first()
而不是->get()
。 Laravel要求你真正维持这些关系。
这意味着即使您在morphOne
和hasOne
之间存在Post
或Image
关系(帖子只能有一张图片,而图片只能属于对于一个帖子,你可以打电话给$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;
}
}