My friends, my life, my style - James S.F. Hsieh

2/02/2010

LiteSQL - SQLite Object Persistent for C++

最近因為工作的原因需要用到 SQLite, Review 現有的 C++ Project, 我發覺我們現有 Project 在使用 SQLite 非常的不方便, 它使用最基本 (原始?!) 的方法自己組合 SQL statement 來操作 DB, 並建立一組 Class hierarchical 來 Modeling DB 的 Schema. 這樣設計的好處在於操作 DB 可以比較自主效能上也許會好些, Class hierarchical 也可以比較複雜. 壞處則是, 許多 DB 的操作 SQL statement 都有固定的 pattern 這個部份可以抽離出來, 但是 Class, statement 與 DB Schema 的對應關係需要人工來維護. 能夠盡量減少人力來維護是我的目標, 所以, 我們需要一個有彈性的 SQLite Object Persistent Library.

我 Survey 了一下現有的 C/C++ SQLite wrapper project, 有支援 Object Persistent 的似乎只有 LiteSQL 這個 open source project, 是用 LiteSQL 必須使用 XML 來定義 DB Schema, 並使用他們提供的 Code generator 來產生 C++ Modeling 的程式碼, 以下是官網上面的 example.

PersonDatabase db("sqlite3", "database=person.db");           
Person person(db);
person.name = "Bob"; // assign values to fields
person.age = 20;
person.update(); // writes a new record to database
我們可以輕易的操作 Person 物件來建立/改變 DB 中的 record, 該例子隱藏了 SQL statement 並且轉換成較我們較直覺得物件化操作, 對於 Relation 的部分, LiteSQL 可以建立 Relation-class 來 Modeling 兩個 Persistent Object 之間的關係, 這樣的設計在 C# 那種具有完整 Reflection 能力的語言中是非常容易實做, 但在 C/C++ 中則是非常困難.

除了Object Persistent 之外, LiteSQL 還提供了一下的 select 語句來方便查詢
PersonDatabase db("sqlite3", "database=person.db");
vector = select(db).all();
Person bob = select(db, Person::Name == "Bob").one();
這個 library 給我不少的啟發, 但我實際上試用它卻有不小的挫折, 原因在於我們使用的 DB Schema 似乎無法產生正確的 class, 畢竟這個計畫目前的狀態仍然是在 proof-of-concept implementation 的階段.

我遇到的另一個問題是, LiteSQL 是使用 Gen-Code 的方式來產生 Modeling Class, 所以, 如果 DB Schema 改變了, 程式碼應該有不小幅度的改變 (我想無法避免), 但是開發過程中 Schema 改變是免不了的, 所以我嘗試設計了一個以 class modeling 為主的方式來產生 DB Schema, 只要遵照一定的 class 設計方式, 就能夠利用類似 Reflection 的方式還產生 Schema 與 record 操作, 主要是配合 macro 跟 template 的方法來實現, 目前我還在設計中, 有機會再跟大家分享 :)