Yii2更新操作时插入新记录问题及多字段模型代码咨询
Hey there, let's fix that frustrating "update creates new records" issue you're hitting in Yii. Based on your description, here's a breakdown of the root causes and actionable solutions:
1. Ensure You're Loading Existing Records (Not Creating New Ones)
The most common reason for this problem is that your UserProfile or UserBillingInfo instances are being initialized as new models instead of loading existing ones. Yii's save() method runs an INSERT if $model->isNewRecord is true, and UPDATE if it's false.
Fix Your Action Code
Rewrite your action to explicitly load existing records, and handle cases where they don't exist (based on your business logic):
public function actionUpdateProfile() { $user_id = Yii::$app->user->identity->id; // Load the main User model (fail fast if not found) $model = User::findOne($user_id); if (!$model) { throw new \yii\web\NotFoundHttpException("User not found"); } // Load existing UserProfile, or initialize a new one ONLY if needed $userProfile = UserProfile::findOne(['user_id' => $user_id]); if (!$userProfile) { // If profiles are required, throw an error here instead of creating a new one $userProfile = new UserProfile(); $userProfile->user_id = $user_id; // Link to the user upfront } // Repeat the same logic for UserBillingInfo $userBillingInfo = UserBillingInfo::findOne(['user_id' => $user_id]); if (!$userBillingInfo) { $userBillingInfo = new UserBillingInfo(); $userBillingInfo->user_id = $user_id; } // Handle POST submission if (Yii::$app->request->isPost) { // Load data into each model separately $model->load(Yii::$app->request->post()); $userProfile->load(Yii::$app->request->post()); $userBillingInfo->load(Yii::$app->request->post()); // Validate all models before saving if ($model->validate() && $userProfile->validate() && $userBillingInfo->validate()) { // Use a transaction to ensure all saves succeed or fail together $transaction = Yii::$app->db->beginTransaction(); try { // Save with false to skip re-validation (we already did it) $model->save(false); $userProfile->save(false); $userBillingInfo->save(false); $transaction->commit(); return $this->redirect(['view-profile']); } catch (\Exception $e) { $transaction->rollBack(); throw $e; // Or handle the error gracefully for users } } } return $this->render('update-profile', [ 'model' => $model, 'userProfile' => $userProfile, 'userBillingInfo' => $userBillingInfo, ]); }
2. Resolve Duplicate Field Conflicts
You mentioned duplicate fields between user and userchildren (like overlapping attribute names). This can cause Yii's load() method to assign values to the wrong model, leading to unexpected behavior.
Fix Your Form Markup
Make sure your form fields are explicitly bound to the correct model. Use Yii's ActiveForm to generate properly namespaced inputs:
<?php $form = \yii\widgets\ActiveForm::begin(); ?> <!-- User model fields --> <?= $form->field($model, 'username')->textInput() ?> <!-- UserProfile model fields (no conflict with User now) --> <?= $form->field($userProfile, 'child_name')->textInput() ?> <?= $form->field($userProfile, 'child_birth_date')->textInput(['type' => 'date']) ?> <?= $form->field($userProfile, 'child_gender')->dropDownList(['male' => 'Male', 'female' => 'Female']) ?> <!-- UserBillingInfo fields --> <?= $form->field($userBillingInfo, 'billing_address')->textarea() ?> <button type="submit" class="btn btn-primary">Update Profile</button> <?php \yii\widgets\ActiveForm::end(); ?>
3. Verify Model Rules & Scenarios
Ensure your models allow mass assignment for the fields you're trying to update. Check the rules() method in UserProfile and UserBillingInfo:
// Example in UserProfile.php public function rules() { return [ // Mark fields as safe for update scenarios [['child_name', 'child_birth_date', 'child_gender'], 'safe', 'on' => ['update']], // Or allow all fields for simplicity (adjust based on security needs) [['child_name', 'child_birth_date', 'child_gender', 'user_id'], 'safe'], ]; }
If you use scenarios, make sure you set the correct scenario on your models before loading data:
$userProfile->scenario = 'update'; $userProfile->load(Yii::$app->request->post());
4. Double-Check for Custom Save Logic
If you've overridden the save() method in any of your models, ensure it's not forcing an INSERT instead of UPDATE. Look for code that manually sets isNewRecord to true, or skips Yii's default save logic.
内容的提问来源于stack exchange,提问作者Pawan

