Laravel 7 - 更新的唯一约束问题

Laravel 7 - Problem with unique constraint on update

我正在尝试向我的模型添加唯一验证,但是当我尝试更新数据时出现错误。

table:

acq_m_budgets
==================================
budget_id serial NOT NULL,
budget_code character varying(15) NOT NULL,
budget_name character varying(100) NOT NULL,
ma_code character varying(10),
start_period timestamp without time zone NOT NULL,
end_period timestamp without time zone NOT NULL,
budget numeric(16) DEFAULT 0,
credit numeric(16) DEFAULT 0,
debet numeric(16) DEFAULT 0,
balance numeric(16) DEFAULT 0,
reserve numeric(16) DEFAULT 0,
created_by character varying(100) NOT NULL,
created_on timestamp without time zone DEFAULT now(),
updated_by character varying(100) NOT NULL,
updated_on timestamp without time zone DEFAULT now(),
CONSTRAINT PK_AcqMBudgets PRIMARY KEY (budget_id),
CONSTRAINT UN_AcqMBudgets UNIQUE (budget_code)

我的模型:AcqMBudgets.php

class AcqMBudgets extends Model
{
    public $timestamps = false;
    protected $primaryKey = 'budget_id';
    public $sortable = ['budget_code', 'budget_name', 'ma_code', 'balance', 'updated_on'];
    protected $fillable = ['budget_code', 'budget_name', 'ma_code', 'start_period', 'end_period', 'budget', 'credit', 'debet', 'balance', 'reserve', 'created_by', 'created_on', 'updated_by', 'updated_on'];
    
    protected $attributes = [
        'budget' => 0,
        'credit' => 0,
        'debet' => 0,
        'balance' => 0,
        'reserve' => 0,
    ];
    
    public static function createRules()
    {
        return [
            'budget_code' => 'required|unique:acq_m_budgets,budget_code|max:15',
            'budget_name' => 'required|max:100',
            'ma_code' => 'max:10',
            'start_period' => 'required',
            'end_period' => 'required',
        ];
    }
    
    public static function updateRules($id)
    {
        return [
            'budget_code' => 'required|unique:acq_m_budgets,budget_code,' . $id . '|max:15',
            'budget_name' => 'required|max:100',
            'ma_code' => 'max:10',
            'start_period' => 'required',
            'end_period' => 'required',
        ];
    }
}

我的控制器:BudgetController.php

...

public function create(Request $request)
    {
        $validateData = $request->validate(AcqMBudgets::createRules());
        
        $model = new AcqMBudgets;
        $post = $request->only($model->getFillable());

        $post['start_period'] = (!empty($post['start_period'])) ? date('Y-m-d', strtotime(str_replace('/', '-', $post['start_period']))) : null;
        $post['end_period'] = (!empty($post['end_period'])) ? date('Y-m-d', strtotime(str_replace('/', '-', $post['end_period']))) : null;
        
        $model->fill($post); 
        $model->save();
        
        return redirect()->route('acq.view.master.budget', ['id' => $model->budget_id, 'rf' => 'a']);
    }

...

public function update($id, Request $request)
    {
        $validateData = $request->validate(AcqMBudgets::updateRules($request->input('budget_id')));
        
        $model = AcqMBudgets::find($id);
        $post = $request->only($model->getFillable());
        
        $post['start_period'] = (!empty($post['start_period'])) ? date('Y-m-d', strtotime(str_replace('/', '-', $post['start_period']))) : null;
        $post['end_period'] = (!empty($post['end_period'])) ? date('Y-m-d', strtotime(str_replace('/', '-', $post['end_period']))) : null;
        
        $model->fill($post);
        $model->save();
        
        return redirect()->route('acq.view.master.budget', ['id' => $model->budget_id, 'rf' => 'e']);
    }

...

在模型上,我已经分离了创建和更新方法的规则。区别在于updateRules(),规则数组中需要一个主键参数。

在控制器上,在 update 功能上,有一个错误指出:SQLSTATE[42703]: Undefined column: 7 ERROR: column "id" does not exist LINE 1: ...from "acq_m_budgets" where "budget_code" = and "id" <> ^ (SQL: select count(*) as aggregate from "acq_m_budgets" where "budget_code" = N01 and "id" <> )

我用的主键是整型递增的,但是由于某些情况,主键的名称不能只是id,所以我改成了budget_id并且已经声明了在模型的开头。根据错误消息,似乎 Laravel 一直在尝试与此 id 字段而不是我声明的字段进行比较。需要做什么来解决这个问题?

代码更新: 我在 createRules 上使用了 Rule 命名空间,在模型上使用了 updateRules:

    public static function createRules()
    {
        return [
            'budget_code' => ['required', Rule::unique('acq_m_budgets', 'budget_code'), 'max:15'],
            'budget_name' => ['required', 'max:100'],
            'ma_code' => ['max:10'],
            'start_period' => ['required'],
            'end_period' => ['required'],
        ];
    }
    
    public static function updateRules($id)
    {
        return [
            'budget_code' => ['required', Rule::unique('acq_m_budgets', 'budget_code')->ignore($id, 'budget_code'), 'max:15'],
            'budget_name' => ['required', 'max:100'],
            'ma_code' => ['max:10'],
            'start_period' => ['required'],
            'end_period' => ['required'],
        ];
    }

当我尝试更新数据时,我对 budget_code 以外的某些字段进行了更改。如果我不更改 budget_code 字段,则不会保存更改,因为它总是给出错误:"budget_code" has already been taken。我用的是dd($post),我改的字段完美传递

我会使用 Rule 命名空间,您可以在其中调用 unique。为此,您必须使用数组来验证规则而不是字符串,无论如何这是提高可读性的更好方法。

Rule::unique有方法ignore()其中第二个参数是id列,这个可以看here.

'budget_code' => [
    'required',
    Rule::unique('acq_m_budgets', 'budget_code')->ignore($id, 'budget_id'),
    'max:15'
]