2

我正在使用 sqlite 数据库将结果存储在嵌入式 C++ 应用程序中。

我有一些单列表,我称之为“域”表,其他表中的列将它们作为外键引用。这些本质上是枚举类型的表,仅在初始化时更改一次。例如,一个存储状态数据类型的表:

CREATE TABLE status_domain (status TEXT PRIMARY KEY NOT NULL UNIQUE);
INSERT INTO status_domain VALUES ('pending');
INSERT INTO status_domain VALUES ('in_progress');
INSERT INTO status_domain VALUES ('error');
INSERT INTO status_domain VALUES ('complete');  
.
.
CREATE TABLE my_other_table (
    .
    .
    status  TEXT NOT NULL,     
    .
    .
    FOREIGN KEY (status) REFERENCES status_domain(status)
);

域表的目的是利用 sqlite 的外键约束(参照完整性)。

写入这些表的 C++ 代码不知道架构。我想知道在 C++ 中复制这些表是否是糟糕的设计。例如:

enum StatusEnum { pending, in_progress, error, complete };

我看到四个选项:

  1. my_other_table在不知道我插入的状态值是否有效的情况下插入。如果状态值无效,这将在运行时失败。
  2. 使用 C++ 枚举复制 ,status_domain以便编译器不会让我执行无效状态的插入。这违反了 DRY 原则,因为如果架构发生更改,我将不得不在这两个地方进行更改。
  3. 报废status_domain表并让 C++ 枚举强制执行有效的数据类型。C++ 代码将是插入这些表的唯一位置,因此这似乎是合理的。然而,在模式中明确声明状态类型是很好的。
  4. 使 sqlite 包装器代码更加了解数据库/模式。我认为这不值得付出努力。

我倾向于选项 2,但犹豫不决,因为它存储的东西可能会在两个不同的地方发生变化。

注意:还有一些(更长的)这样的表格我没有分享。

4

3 回答 3

1

您正在谈论维护数据库模式和过程语言代码之间的一致性的众所周知的问题。这个问题没有很好的解决方案。有几种方法,例如 Microsoft 的 EntityFramework。它们都不是完美的。

我建议您考虑以下解决方案:

  1. 编写一段 C++ 代码,它将从枚举中生成 SQL 查询(C++ 中没有反射,但有一个选项可以检查switch语句中是否存在所有枚举成员)。一旦你改变了你的枚举,你应该重新创建你的 SQL 查询,它应该重建你的表并运行这个查询。

  2. 编写 SQL 查询,该查询将生成一段 C++ 代码,其中包含表的新状态中的枚举。更改表后,您必须重新运行查询,然后重新编译 C++ 代码。

这些程序不是全自动的,但至少它们给出了一些可以遵循的策略。

于 2013-01-06T04:34:13.100 回答
1

根据您所展示的内容,我倾向于选项 3(废品status_domain)。作为参考,我看不到该表真正为您提供的内容(没有您尚未拥有的关联数据,您my_other_table需要用于连接或其他操作)。

my_other_table你总是可以这样做:

status TEXT NOT NULL CHECK (status IN ('pending', 'in_progress', ...))

也没有必要为此目的使用字符串。C++enum值应该可以正常工作,并且也可以通过CHECK约束进行检查。

于 2013-01-06T05:05:10.313 回答
0

那么,您似乎想要选择选项 2。我有点假设原因在于您无法共享的表格。在那种情况下,我会使用GNU autogen并执行以下操作:

状态.def

自动生成定义状态;

状态 = { 数字 =“1”; 名称="待定"; };
状态 = { 数 =“2”;name="in_progress"; };
状态 = { 数字 =“3”; 名称="错误"; };
状态 = { 数字 =“4”; 名称=“完成”;};

根.tpl

[+ autogen5 模板
sql=%s.sql
h=%sh
(setenv "SHELL" "/bin/sh") +][+ CASE (后缀) +][+ == sql +]
CREATE TABLE status_domain (id INTEGER PRIMARY KEY, status TEXT NOT NULL UNIQUE);
[+ FOR status "\n" +]INSERT INTO status_domain VALUES ([+num+], '[+name+]');[+
ENDFOR+]
创建表 my_other_table (
     .
     .
    status_domain_id 整数,     
     .
     .
    外键 (status_domain_id) 参考 status_domain(id)
);
[+ == h +]枚举StatusDomainEnum {
[+ FOR 状态 ",\n" +] [+name+] = [+num+][+ENDFOR+]
};
[+ESAC+]

哪个输出:

状态.h

枚举状态域枚举 {
    待定 = 1,
    in_progress = 2,
    错误 = 3,
    完成 = 4
};

状态.sql

CREATE TABLE status_domain (id INTEGER PRIMARY KEY, status TEXT NOT NULL UNIQUE);
INSERT INTO status_domain VALUES (1, 'pending');
INSERT INTO status_domain VALUES (2, 'in_progress');
INSERT INTO status_domain VALUES (3, 'error');
INSERT INTO status_domain VALUES (4, 'complete');
创建表 my_other_table (
    .
    .
    status_domain_id 整数,     
    .
    .
    外键 (status_domain_id) 参考 status_domain(id)
);
于 2013-01-07T05:16:08.603 回答