可以在应用程序代码中复制数据库数据吗?

时间:2013-01-06 03:19:59

标签: c++ database sqlite

我使用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包装器代码更容易识别数据库/模式。我认为这不值得付出努力。
  5. 我倾向于选择2,但我犹豫不决,因为它存储的东西可能会在两个不同的地方发生变化。

    注意:还有一些(更长)的表格,我不会分享。

3 个答案:

答案 0 :(得分:1)

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

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

  1. 编写一段C ++代码,它将从您的枚举中生成一个SQL查询(C ++中没有反射,但是有一个选项可以检查switch中是否存在所有枚举成员声明)。更改枚举后,应重新创建应重建表并运行此查询的SQL查询。

  2. 编写SQL查询,该查询将生成一些带有枚举的C ++代码,这些代码来自表的新状态。更改表后,必须重新运行查询,然后重新编译C ++代码。

  3. 这些程序并非完全自动化,但至少它们提供了一些可以遵循的政策。

答案 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)
);