我使用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 };
我看到四个选项:
my_other_table
。如果状态值无效,这将在运行时失败。status_domain
,以便编译器不允许我执行具有无效状态的插入。这违反了DRY原则,因为如果架构发生变化,我将不得不在这两个地方进行更改。status_domain
表并让C ++枚举强制执行有效的数据类型。 C ++代码将是插入这些表的唯一位置,因此这似乎是合理的。但是,在模式中显式声明状态类型是很好的。我倾向于选择2,但我犹豫不决,因为它存储的东西可能会在两个不同的地方发生变化。
注意:还有一些(更长)的表格,我不会分享。
答案 0 :(得分:1)
您正在谈论维护数据库架构和过程语言代码之间一致性的众所周知的问题。这个问题没有很好的解决方案。有几种方法,如Microsoft的EntityFramework。它们都不是完美的。
我建议您考虑以下解决方案:
编写一段C ++代码,它将从您的枚举中生成一个SQL查询(C ++中没有反射,但是有一个选项可以检查switch
中是否存在所有枚举成员声明)。更改枚举后,应重新创建应重建表并运行此查询的SQL查询。
编写SQL查询,该查询将生成一些带有枚举的C ++代码,这些代码来自表的新状态。更改表后,必须重新运行查询,然后重新编译C ++代码。
这些程序并非完全自动化,但至少它们提供了一些可以遵循的政策。
答案 1 :(得分:1)
根据你所展示的内容,我倾向于选项3(废料status_domain
)。参考,我没有看到该表真正给你的是什么(在my_other_table
中你没有关联数据或其他操作所需的相关数据)。
在my_other_table
中,您可以随时执行:
status TEXT NOT NULL CHECK (status IN ('pending', 'in_progress', ...))
实际上也没有必要为此目的使用字符串。 C ++ enum
值应该可以正常工作,也可以通过CHECK
约束进行检查。
答案 2 :(得分:0)
似乎你想要继续选择2。我有点假设原因在于你无法分享的表格。在那种情况下,我会选择GNU autogen并执行以下操作:
<强> status.def 强>
autogen definitions status; status = { num="1"; name="pending"; }; status = { num="2"; name="in_progress"; }; status = { num="3"; name="error"; }; status = { num="4"; name="complete"; };
<强> gen.tpl 强>
[+ autogen5 template sql=%s.sql h=%s.h (setenv "SHELL" "/bin/sh") +][+ CASE (suffix) +][+ == 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+] CREATE TABLE my_other_table ( . . status_domain_id INTEGER, . . FOREIGN KEY (status_domain_id) REFERENCES status_domain(id) ); [+ == h +]enum StatusDomainEnum { [+ FOR status ",\n" +] [+name+] = [+num+][+ENDFOR+] }; [+ESAC+]
哪个输出:
<强> status.h 强>
enum StatusDomainEnum { pending = 1, in_progress = 2, error = 3, complete = 4 };
和
<强> status.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'); CREATE TABLE my_other_table ( . . status_domain_id INTEGER, . . FOREIGN KEY (status_domain_id) REFERENCES status_domain(id) );