数据类型(字段)表上的雄辩关系

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 数据类型的表上的字段

使用现有表模式上的数据透视表在雄辩模型中指定关系字段

数据库表上的 1 对 1 关系有味道吗?

Laravel:在父表上与 *where* 建立雄辩的关系,而不是 *find*

Django的Mov逻辑的管理特色

表上的 PHP PDO 查询错误具有 json 数据类型(MySQL 5.7.8-rc)