数据类型(字段)表上的雄辩关系
Posted
技术标签:
【中文标题】数据类型(字段)表上的雄辩关系【英文标题】:Eloquent relation on data types (fields) table 【发布时间】:2020-06-02 18:52:11 【问题描述】:这是我的表,User 是经典的 Auth 表:
数据类型
+----+--------------+
| id | field |
+----+--------------+
| 1 | address |
| 2 | mobile_phone |
| 3 | city |
+----+--------------+
用户数据
+----+----------+--------------+---------+
| id | value | data_type_id | user_id |
+----+----------+--------------+---------+
| 1 | Milan | 3 | 1 |
| 2 | 99123233 | 2 | 1 |
+----+----------+--------------+---------+
我目前的疯狂模特:
class User extends Authenticatable
public function field($field)
$field=DataType::where('field',$field)->first();
return $this->hasMany('App\UserData')->where('datatype_id',(isset($field->id) ? $field->id : 0));
当然,当我必须找到值时它可以正常工作:
auth()->user()->field('mobile_phone')->get();
但是如何设置或更新新手机呢?
【问题讨论】:
您的意思是要将“用户数据”中的“值”更改为不同的电话号码? 更改或添加一个新的。正确的关系 【参考方案1】:另一种方法是将 User 和 DataTypes 链接为多对多关系并使用范围来处理它。
首先,将 UserData 表更改为 dataTypeUser,这样您就可以使用默认的 eloquent 关系。 在任何模型中放置belongsToMany 关系。 用户模型
public function dataTypes()
return $this->belongsToMany('App\DataType')
->withPivot(['value']);
public function scopeField($query, $field)
return $query->whith(['dataTypes'=>function($q)use($field)
$q->where('data_types.field',$field);
]);
数据类型模型
public function users()
return $this->belongsToMany('App\User')
->withPivot(['value']);
要获得一些价值,您可以使用$field = $user->field('something')->first()
来保存新数据,可以使用$user->field('something')->updateExistingPivot($field->id,['value'=>$newValue])
。
无论如何,如果您没有很多相同类型的数据附加到您的用户(例如多个电话号码),那么使用一个扩展用户迁移的单个表或最后一个 userData 可能是一种更好的方法每个数据类型的列。在小型应用程序中,您没有问题,但随着应用程序的增长,性能将成为许多表和许多关系的问题。
为避免声明过长,您可以覆盖魔术方法 __get 和 __set。两者都在 Illuminate\Database\Eloquent\Model 中声明,因此请放入您的用户模型中:
public function __get($key)
return $this->getAttribute($key) ?? $this->getAttributesFromPivot($key);
public function __set($key, $value)
if(in_array($key,array_keys($this->original)))
$this->setAttribute($key, $value);
else
$this->setAttributeFromPivot($key, $value);
public function setAttributeFromPivot($key, $value)
$this->dataTypes()->where('field',$key)->update(['value'=>$value]);
protected function getAttributesFromPivot($key)
return $this->dataTypes()
->where('field',$key)
// use this to get only one value direct
->first()->pivot->value ?? null;
// or use this to get all of them as array
// ->get()
// ->map(function($item) return $item->pivot->value;) ?? null;
在这种方法中,您可以使用$user->city
来获取字段城市或另一个替换->city
。或者您可以使用$user->address = 'foo';
在数据透视表中设置新值。注意它会直接更新数据库。
现在,如果您不习惯覆盖这些方法,则无需这样做。将 setAttributeFromPivot 和 getAttributeFromPivot 的签名更改为 public function getField($key)
和 public function setField($key, $value)
。现在您可以将它们用作常用方法。
【讨论】:
在尝试使用 $query->dataTypes() 而不是 $this->dataTypes() 时调用未定义的方法 Illuminate\Database\Eloquent\Builder::dataTypes() 对不起,我之前没有测试过。我正在编辑答案。 在$q->where('data_types.field',$field);
中,我将data_types
称为表名,因为这是Larvel/Eloquent 的默认值。如果您使用不同的名称,请编辑它。以上是关于数据类型(字段)表上的雄辩关系的主要内容,如果未能解决你的问题,请参考以下文章
如何在 EF Code First 中声明具有 Medium Blob 数据类型的表上的字段