Drogon 1.7.1插入SQL未含主键device_id致外键约束失败问题
问题
我使用SQLite数据库与Drogon 1.7.1版本,创建了如下表:
CREATE TABLE IF NOT EXISTS "storage_device_info" ( "device_id" INTEGER, "volume_name" TEXT, "volume_description" TEXT, "volume_drive_letter" TEXT, "volume_size" INTEGER, "volume_file_system" TEXT, "storage_name" TEXT, "storage_description" TEXT, "storage_capacity" INTEGER, "storage_serial" TEXT, PRIMARY KEY("device_id"), FOREIGN KEY("device_id") REFERENCES "device"("id") );
通过Drogon CLI工具为该表生成了StorageDeviceInfo模型,创建模型对象并设置合法的device_id后,调用Mapper<StorageDeviceInfo>.insert插入数据时,出现「Foreign key constraint failed error」错误。查看生成的模型代码,发现sqlForInserting函数未包含device_id参数,代码如下:
std::string sqlForInserting(bool &needSelection) const { std::string sql="insert into " + tableName + " ("; size_t parametersCount = 0; needSelection = false; if(dirtyFlag_[1]) { sql += "volume_name,"; ++parametersCount; } if(dirtyFlag_[2]) { sql += "volume_description,"; ++parametersCount; } if(dirtyFlag_[3]) { sql += "volume_drive_letter,"; ++parametersCount; } if(dirtyFlag_[4]) { sql += "volume_size,"; ++parametersCount; } if(dirtyFlag_[5]) { sql += "volume_file_system,"; ++parametersCount; } if(dirtyFlag_[6]) { sql += "storage_name,"; ++parametersCount; } if(dirtyFlag_[7]) { sql += "storage_description,"; ++parametersCount; } if(dirtyFlag_[8]) { sql += "storage_capacity,"; ++parametersCount; } if(dirtyFlag_[9]) { sql += "storage_serial,"; ++parametersCount; } if(parametersCount > 0) { sql[sql.length()-1]=')'; sql += " values ("; } else sql += ") values ("; if(dirtyFlag_[1]) { sql.append("?,"); } if(dirtyFlag_[2]) { sql.append("?,"); } if(dirtyFlag_[3]) { sql.append("?,"); } if(dirtyFlag_[4]) { sql.append("?,"); } if(dirtyFlag_[5]) { sql.append("?,"); } if(dirtyFlag_[6]) { sql.append("?,"); } if(dirtyFlag_[7]) { sql.append("?,"); } if(dirtyFlag_[8]) { sql.append("?,"); } if(dirtyFlag_[9]) { sql.append("?,"); } if(parametersCount > 0) { sql.resize(sql.length() - 1); } sql.append(1, ')'); LOG_TRACE << sql; return sql; }
请问这是框架bug还是我的操作有误?该如何正确插入模型数据?
分析与解决方案
这不是操作错误,是Drogon 1.7.1版本CLI工具的生成逻辑问题:它默认将主键字段排除在插入SQL之外,即便这个主键同时是外键且需要手动指定值(而非自增)。
解决办法
有两种可行的修复方式:
手动修改生成的模型代码
在sqlForInserting函数中,添加device_id的处理逻辑,确保它被包含在插入字段和参数列表中:std::string sqlForInserting(bool &needSelection) const { std::string sql="insert into " + tableName + " ("; size_t parametersCount = 0; needSelection = false; // 添加device_id的判断逻辑 if(dirtyFlag_[0]) // device_id是表中第一个字段,对应dirtyFlag索引0 { sql += "device_id,"; ++parametersCount; } if(dirtyFlag_[1]) { sql += "volume_name,"; ++parametersCount; } // 保留原有其他字段的判断代码... if(dirtyFlag_[9]) { sql += "storage_serial,"; ++parametersCount; } if(parametersCount > 0) { sql[sql.length()-1]=')'; sql += " values ("; } else sql += ") values ("; // 添加device_id的参数占位符 if(dirtyFlag_[0]) { sql.append("?,"); } if(dirtyFlag_[1]) { sql.append("?,"); } // 保留原有其他参数的代码... if(dirtyFlag_[9]) { sql.append("?,"); } if(parametersCount > 0) { sql.resize(sql.length() - 1); } sql.append(1, ')'); LOG_TRACE << sql; return sql; }同时要确保模型类的
setDeviceId方法中正确标记dirtyFlag_[0] = true;,这样设置device_id后,字段会被识别为需要插入的脏数据。使用自定义SQL插入
绕过生成的模型插入方法,直接用Drogon的数据库客户端执行自定义插入SQL:auto client = drogon::app().getDbClient(); client->execSqlAsync( "INSERT INTO storage_device_info (device_id, volume_name, volume_description, volume_drive_letter, volume_size, volume_file_system, storage_name, storage_description, storage_capacity, storage_serial) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", {deviceId, volumeName, volumeDesc, driveLetter, volumeSize, fileSystem, storageName, storageDesc, storageCapacity, storageSerial}, [](const drogon::DbClient::SqlResult &result) { // 插入成功后的处理逻辑 }, [](const drogon::DbException &e) { // 错误处理逻辑 } );
额外说明
如果device_id不需要手动指定,可修改表结构将其设为自增主键:
CREATE TABLE IF NOT EXISTS "storage_device_info" ( "device_id" INTEGER PRIMARY KEY AUTOINCREMENT, -- 其他字段保持不变 FOREIGN KEY("device_id") REFERENCES "device"("id") );
这样Drogon会自动处理主键生成,不会触发外键约束错误。
内容的提问来源于stack exchange,提问作者Kliment Nechaev
相关产品推荐
相关产品推荐

