Laravel跨数据库复制Eloquent模型记录报错排查
我需要将mysqlProducts数据库中ind_products表内指定product_id的记录复制到mysqlOrders数据库的cart_ind_products表中,同时设置指定的cart_product_id。
我的模型定义如下:
class IndProduct extends Model { use HasFactory; protected $connection = 'mysqlProducts'; protected $table = "ind_products"; protected $fillable = [ 'product_id', 'name', 'category', 'subcategory', 'description', 'price_VAT_excl_per_unit', 'price_VAT_incl_per_unit', 'weight', 'breed', 'kind', 'age', 'bio', 'grass_fed', 'drying_time', 'nr_of_pieces', 'lifestyle', 'part_of_animal', 'confirmed', 'saved', ]; // 单个商品属于一个商品(关联关系) public function products() { return $this->setConnection('mysqlProducts')->belongsTo(Product::class, 'product_id', 'id'); } } class CartIndProduct extends Model { use HasFactory; protected $connection = 'mysqlOrders'; protected $table = "cart_ind_products"; protected $fillable = [ 'cart_product_id', 'product1_id', 'name', 'category', 'subcategory', 'description', 'price_VAT_excl_per_unit', 'price_VAT_incl_per_unit', 'weight', 'breed', 'kind', 'age', 'bio', 'grass_fed', 'drying_time', 'nr_of_pieces', 'lifestyle', 'part_of_animal', 'confirmed', 'saved', ]; // 购物车单个商品属于一个购物车商品(关联关系) public function cart_products() { return $this->setConnection('mysqlOrders')->hasOne(CartProduct::class, 'cart_product_id', 'id'); } }
第一次尝试的代码及错误
控制器代码
public function createCartIndProducts(Request $request, $cart_product_id, $product_id) { $ind_products = IndProduct::on('mysqlProducts')->where('product_id', '=', $product_id)->get()->toArray(); foreach($ind_products as $ind_product) { CartIndProduct::on('mysqlOrders')->insert($ind_product); } return response()->json([ "status" => 1, "message" => "Cart individual products registered successfully in database.", ], 200); }
错误信息
SQLSTATE[22007]: 无效的日期时间格式:1292 列 'created_at' 的日期时间值 '2022-10-28T19:54:12.000000Z' 不正确(SQL:insert into
cart_ind_products(id,name,category,subcategory,description,price_VAT_excl_per_unit,price_VAT_incl_per_unit,weight,created_at,updated_at,product_id,breed,kind,age,bio,grass_fed,drying_time,nr_of_pieces,lifestyle,part_of_animal,confirmed,saved) values (656, ?, Aardappelen, ?, ?, 0.00, 0.00, ?, 2022-10-28T19:54:12.000000Z, 2022-10-28T19:54:12.000000Z, 903, bjbg, ?, ?, 0, ?, ?, ?, ?, ?, 1, 1))
第二次尝试的代码及错误
控制器代码
public function createCartIndProducts(Request $request, $cart_product_id, $product_id) { $ind_products = IndProduct::on('mysqlProducts')->where('product_id', '=', $product_id)->get(); foreach($ind_products as $ind_product) { $cart_ind_product = IndProduct::on('mysqlProducts')->$ind_product->replicate()->fill( ['cart_product_id' => $cart_product_id, ] ); $cart_ind_product->CartIndProduct::on('mysqlOrders')->save(); } return response()->json([ "status" => 1, "message" => "Cart individual products registered successfully in database.", // "data" => $cart_ind_products, ], 200); }
错误信息
属性 [{"id":656,"name":null,"category":"Aardappelen","subcategory":null,"description":null,"price_VAT_excl_per_unit":"0.00","price_VAT_incl_per_unit":"0.00","weight":null,"created_at":"2022-10-28T19:54:12.000000Z","updated_at":"2022-10-28T19:54:12.000000Z","product_id":903,"breed":"bjbg","kind":null,"age":null,"bio":0,"grass_fed":null,"drying_time":null,"nr_of_pieces":null,"lifestyle":null,"part_of_animal":null,"confirmed":1,"saved":1}] 不存在于Eloquent构造器实例上。
请问我哪里操作有误?
第一次尝试的错误原因
- 日期格式不兼容:
get()->toArray()会把Eloquent模型的created_at/updated_at转换成带时区的ISO格式字符串,但MySQL的datetime字段不支持这种格式,导致插入失败。 - 字段不匹配:原表的
product_id在目标表中对应product1_id,直接插入会导致字段映射错误,同时目标表必填的cart_product_id未设置。 - 主键冲突风险:直接复制原表的
id字段,可能和目标表已有主键冲突。
第二次尝试的错误原因
代码语法错误:IndProduct::on('mysqlProducts')->$ind_product写法完全错误,$ind_product已经是查询返回的IndProduct实例,不需要再通过模型构造器调用,这行代码相当于试图访问Eloquent构造器上以整个模型JSON为名称的属性,必然报错。
正确的实现代码
public function createCartIndProducts(Request $request, $cart_product_id, $product_id) { // 从源数据库获取目标记录 $indProducts = IndProduct::on('mysqlProducts') ->where('product_id', $product_id) ->get(); foreach ($indProducts as $indProduct) { // 复制模型实例,排除主键、时间戳字段 $cartIndProduct = $indProduct->replicate(['id', 'created_at', 'updated_at']); // 映射字段并设置cart_product_id $cartIndProduct->fill([ 'cart_product_id' => $cart_product_id, 'product1_id' => $indProduct->product_id // 源表product_id对应目标表product1_id ]); // 切换到目标数据库并保存 $cartIndProduct->setConnection('mysqlOrders')->save(); } return response()->json([ "status" => 1, "message" => "购物车单个商品已成功注册到数据库。", ], 200); }
关键改进点
- 使用
replicate()复制模型:自动处理模型属性,避免手动数组转换带来的格式问题,同时可指定排除不需要复制的字段(如主键、时间戳)。 - 明确字段映射:将源表
product_id对应到目标表product1_id,同时设置必填的cart_product_id。 - 切换数据库连接:通过
setConnection()为复制后的模型指定目标数据库,确保保存到正确的表中。 - 自动生成时间戳:Laravel会自动为新保存的模型生成符合MySQL格式的
created_at和updated_at值,无需手动处理。
内容的提问来源于stack exchange,提问作者Isabelle

