2013-01-06 33 views
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) 
); 

域表的目的是要利用源碼的外鍵約束(參照完整性)。

寫入這些表的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,但我猶豫不決,因爲它存儲的東西可能會在兩個不同的地方發生變化。

注意:還有一些這樣的表格(我沒有分享)。

回答

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) 
); 
1

您正在談論衆所周知的維護數據庫模式和過程語言代碼之間一致性的問題。這個問題沒有很好的解決方案。像Microsoft的EntityFramework有幾種方法。沒有一個是完美的。

我會建議你考慮以下解決方案:

  1. 寫一段C++代碼,將生成一個SQL查詢您的枚舉(沒有在C++中反映,但有一個選項它檢查所有枚舉成員是否存在於switch聲明中)。一旦你改變你的枚舉,你應該重新創建你的SQL查詢,它應該重建你的表並運行這個查詢。

  2. 編寫SQL查詢,該查詢將生成帶有枚舉的C++代碼片段,使其不在表格的新狀態之列。一旦你改變你的表格,你將不得不重新運行你的查詢,然後重新編譯你的C++代碼。

這些程序不是完全自動的,但至少它們給出了一些可以遵循的策略。

1

隨着你所示,我會傾向於選項3(報廢status_domain)。我不明白,這張桌子真的給你帶來了什麼(沒有你在my_other_table中沒有的關聯數據,你需要進行連接或其他操作)。

my_other_table你總是可以這樣做:

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

真的還有沒有必要使用字符串用於此目的。 C++ enum值應該正常工作,也可以通過CHECK約束來檢查。

+0

我想檢查是不是具有附加表的更好,但它仍然沒有擺脫重複的問題,這是我可能必須忍受的事情。 – izak

相關問題