在無反射、無 ORM 的 C 語言中,實現類似 Hibernate 的體驗:結構體 ↔ 表自動映射、CRUD 統一入口、類型安全。
// 業務實體
typedef struct User {
int id;
char *name;
char *password;
} User;
// 通用鏈表承載查詢結果
typedef struct SelectNode {
void *value; // 指向具體結構體實例
struct SelectNode *next;
} SelectNode;
typedef void (*ValueFreeFunc)(void *); // 釋放回調
SelectNode *select_list_new(void);
void select_list_free(SelectNode *head, ValueFreeFunc free_fn);
#define SELECT_(cols, table, where) "SELECT " cols " FROM " #table " WHERE " #where
#define INSERT_(table, cols, vals) "INSERT INTO " #table " (" cols ") VALUES (" vals ")"
#define UPDATE_(table, set, where) "UPDATE " #table " SET " set " WHERE " #where
#define DELETE_(table, where) "DELETE FROM " #table " WHERE " #where
// 變參執行器
#define sql_exec(fmt, ...) _sql_exec(fmt, __VA_ARGS__)
#define select_tbl(res, fmt, ...) _select_tbl((void**)(res), fmt, __VA_ARGS__)
int _sql_exec(const char *fmt, ...) {
char sql[1024];
va_list ap; va_start(ap, fmt);
vsnprintf(sql, sizeof(sql), fmt, ap);
va_end(ap);
char *err = NULL;
int rc = sqlite3_exec(db, sql, NULL, NULL, &err);
if (rc != SQLITE_OK) {
fprintf(stderr, "SQL錯誤: %s\nSQL: %s\n", err, sql);
sqlite3_free(err);
}
return rc;
}
// 表名 → 映射函數 的註冊表(簡化版用 if-else)
void *map_user(sqlite3_stmt *stmt) {
User *u = calloc(1, sizeof(User));
int cols = sqlite3_column_count(stmt);
for (int i = 0; i < cols; i++) {
const char *col = sqlite3_column_name(stmt, i);
if (strcmp(col, "id") == 0) u->id = sqlite3_column_int(stmt, i);
else if (strcmp(col, "name") == 0) u->name = strdup((char*)sqlite3_column_text(stmt, i));
else if (strcmp(col, "password") == 0) u->password = strdup((char*)sqlite3_column_text(stmt, i));
}
return u;
}
int _select_tbl(void **result, const char *fmt, ...) {
char sql[1024];
va_list ap; va_start(ap, fmt);
vsnprintf(sql, sizeof(sql), fmt, ap);
va_end(ap);
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
SelectNode *head = NULL, *tail = NULL;
while (sqlite3_step(stmt) == SQLITE_ROW) {
const char *tbl = sqlite3_column_table_name(stmt, 0);
void *obj = NULL;
if (strcmp(tbl, "User") == 0) obj = map_user(stmt);
// else if ... 其他表映射
if (obj) {
SelectNode *node = select_list_new();
node->value = obj;
if (!head) head = tail = node;
else { tail->next = node; tail = node; }
}
}
*result = head;
sqlite3_finalize(stmt);
return 0;
}
// 插入
User u = {0, "alice", "secret"};
sql_exec(INSERT_(User, "id,name,password", "%d,'%s','%s"), u.id, u.name, u.password);
// 查詢
SelectNode *list = NULL;
select_tbl(&list, SELECT_("*", User, "name='alice'"));
for (SelectNode *n = list; n; n = n->next) {
User *u = n->value;
printf("%d %s %s\n", u->id, u->name, u->password);
}
select_list_free(list, (ValueFreeFunc)user_free); // 釋放字符串與節點
unordered_map<string, MapperFunc> 替換 if-else,支援動態加載。sqlite3_stmt* 避免重複解析。BEGIN/COMMIT/ROLLBACK 宏。sqlite3* 池。通過「SQL 模板宏 + 變參執行器 + 表名分發映射函數 + 通用鏈表結果集」,在 C 語言中構建出類型相對安全、語法接近 ORM 的數據庫訪問層,適合中小型嵌入式/桌面項目。