You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 12:55:57