【问题标题】:android sqlite foreign key update failsandroid sqlite外键更新失败
【发布时间】:2015-03-06 03:07:27
【问题描述】:

我想知道是否有人偶然发现了 sqlite 外键的奇怪行为。

当我更新指向另一个表主键 parcours (eid) 并被声明为外键的键变体 (parcours_id) 时,会出现我的问题。

涉及的表格有:

CREATE TABLE parcours(
    eid character varying(36) PRIMARY KEY,
    name character varying(50),
    comment text,
    location_id character varying(36),
    owner_id character varying(36),
    change_id integer NOT NULL,
    change_flag smallint NOT NULL DEFAULT 1,
    CONSTRAINT fk_location_id FOREIGN KEY (location_id)
      REFERENCES location (eid) 
      ON UPDATE CASCADE 
      ON DELETE RESTRICT
)



CREATE TABLE variant (
    eid character varying(36) PRIMARY KEY,
    parcours_id character varying(36) NOT NULL,
    name character varying(50),
    comment text,
    created TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
    active smallint NOT NULL DEFAULT 1,
    selected smallint NOT NULL DEFAULT 0,
    tgt_count integer NOT NULL,
    owner_id  character varying(36) 
      DEFAULT '687baa6e-556f-43f2-897a-f1dfb371541a',
    change_id integer NOT NULL,
    change_flag smallint NOT NULL DEFAULT 1,
    CONSTRAINT fk_parcours_id FOREIGN KEY (parcours_id)
    REFERENCES parcours (eid) 
      ON UPDATE CASCADE 
      ON DELETE RESTRICT 
)

variant(parcours_id) 到 parcours(eid) 的外键关系在插入时完美运行,但在更新时失败

android.database.sqlite.SQLiteException: foreign key mismatch: , while compiling: UPDATE variant SET parcours_id=?,name=?,comment=?,created=?,active=?,selected=?,tgt_count=?,owner_id=?,change_id=?,change_flag=? WHERE eid=?

现在这个问题有点哲学,因为此时我不需要更新密钥变体(parcours_id),因为它没有改变。我决定只执行一次更新功能,始终更新除主键之外的所有字段。一般来说,我不希望有问题的值会改变,所以我可以将它排除在更新之外。

在我看来,我的实现没问题,因为如果我禁用数据库上的外键而不更改它的任何其他工作,则外键会正确更新,并且更新后数据库的完整性是完整的。

对我来说,这证明问题不是由我的实现引起的,但似乎是对 sqlite 如何处理外键更新的普遍误解。

有什么建议吗?

编辑: 从更新中删除关键变量(parcours_id)后,我仍然得到一个 SQLITE 异常:

android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed

SQL 语句是:

UPDATE variant SET name=?,comment=?,created=?,active=?,selected=?,tgt_count=?,owner_id=?,change_id=?,change_flag=? WHERE eid=?

【问题讨论】:

    标签: android database sqlite


    【解决方案1】:

    variant(parcours_id) 到 parcours(eid) 的外键关系在插入时完美运行,但在更新时失败

    android.database.sqlite.SQLiteException: foreign key mismatch: , while compiling: UPDATE variant SET parcours_id=?,name=?,comment=?,created=?,active=?,selected=?,tgt_count=?,owner_id=?,change_id=?,change_flag=? WHERE eid=?
    

    鉴于您的外键约束,如果您尝试在 UPDATE 语句中为 parcours_id 设置的值在 eid 列中不存在,则更新应该失败parcours 中的任何行。例如:

    SELECT eid FROM parcours ORDER BY eid;

    eid
    -----
    a
    b
    c
    

    UPDATE variant SET parcours_id = 'zzz' WHERE eid = '123'; 应该失败,因为 parcourseid 列中不存在值 zzz

    另一方面,UPDATE variant SET parcours_id = 'b' WHERE eid = '123'; 应该可以正常工作,因为值 b 确实存在。

    我刚刚使用您的 CREATE TABLE 语句(也创建了一个假的 location 表)测试了这种行为,它按预期工作。您可以将您在UPDATE variant 语句中使用的parcours_id 值与SELECT eid FROM parcours ORDER BY eid; 的输出进行比较以进行验证。

    请参阅Sqlite Foreign Key Support 了解更多信息。

    编辑:从更新中删除关键变量(parcours_id)后,我仍然得到一个 SQLITE 异常:

    android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed
    

    这可能与其他约束有关,例如NOT NULL。检查您在UPDATE 语句中传递的参数是否有任何null 值,尤其是tgt_countchange_id,因为这些列没有默认值。

    您还可以尝试从 CREATE TABLE variant 语句中删除 NOT NULL 约束并运行更新以验证 NOT NULL 是否是有问题的约束。

    【讨论】:

    • 也许我说得不够清楚,但我输入的数据不太可能是问题所在。外键在插入和稍后更新对象之间实际上并没有改变,我可以看到,它工作正常,因为我更新的对象在更新后仍然与外键的目标正确关联。我还使用调试语句来确保我更新的密钥更新为相同的值。
    • 澄清一下,你是说当你执行更新时,你在更新时使用的外键值和更新时记录中的值是一样的吗?而且您遇到“外键不匹配”的运行时错误?我使用您的CREATE TABLE 语句测试了这个场景(Android 5.0.1,API 21),但这并没有发生。你运行的是什么版本的安卓?另外,您是否解决了第二个约束错误?
    • 是的,这正是我所看到的。我一直在使用 API 级别 14 的 Android 虚拟设备进行测试。但我同意这听起来很奇怪,我将不得不再次查看它并检查我是否忽略了某些东西
    • 从那时起,Android 中的sqlite 发生了一些重大变化——例如,shell.c API 14shell.c API 21——这或许可以解释为什么我们会遇到不同的行为。也许尝试在模拟器中测试更高的 API 级别?
    • 我已将我的代码的关键部分提取到一个测试应用程序中,并且在那里它可以正常执行。所以看起来问题出在我的代码中。我将不得不向测试应用程序添加更多代码,直到它无法找到问题为止。当我有结果时,我会在这里发布我的结果。
    猜你喜欢
    • 2018-09-17
    • 1970-01-01
    • 2020-10-18
    • 1970-01-01
    • 2014-10-04
    • 1970-01-01
    • 2021-12-28
    • 2018-05-17
    • 1970-01-01
    相关资源
    最近更新 更多