文章目錄
- 【譯】Simple MySQL ORM for C
原文連結:http://daoluan.net/blog/?p=1613
一直不知道有ORM這種東西,直到和 @海坡 交流後才接觸。
在項目中,需要將資料存放區到資料庫中,首先想到的是產生各種raw SQL的解決方案。但隨著項目的進展,發現它很不靈活。譬如可能因為有新的需求,在資料庫student表中添加dept_no欄位,那在各種raw SQ中就需要進行修改了,工程浩大。如果操作(插入\修改\刪除)資料庫表中的資料,和操作資料對象一樣,可以簡化很多的操作,便於資料層的變更,而不必修改邏輯層代碼。
//項目隨手摘錄的一個構造插入指定對象資料的INSERT語句的方法。int gtd_genInsertSql(struct task_t &toinsert,char *sql, int nUserID){ int curr = 0; //task_id | user_id | strtext curr += sprintf(sql,"insert into task values(%d,%d,'%s',", toinsert.id,nUserID/*user_id*/,toinsert.strtext); //ctime char buffer[32]; ::memset(buffer,0,sizeof(buffer)); strftime(buffer,32,"'2012-%m-%d %H-%M-%S',",&(toinsert.ctime)); strncpy(sql+curr,buffer,strlen(buffer)); curr += strlen(buffer);...... *(sql + curr) = ')'; curr++; return curr;}
ORM,即對象關係映射,ORM的設計就是資料庫持久層的設計。目前流行有一些成熟的ORM架構,對應各種語言都有。
因為項目實際需要,挑選了一個輕便的架構:Simple MySQL ORM for C。google了下,只發現有Simple MySQL ORM for C作者的一篇英文博文介紹而已:http://ales.jikos.cz/smorm/。「打米量家底」,因為那篇文章不太長,所以把它翻譯過來了。記得年前 @獨酌逸醉 有提到過,他有翻譯StackOverFlow上的精華帖。現在看來,譬如對C++熟悉,完全可以去看看外國的程式員社區。一方面你本身是程式員,專業對口,認得大多數單詞;另一方面,國外高手也多,不為是提高技術的好機會;最後,它確實提高英語的好方法,贊一個。
下面是《Simple MySQL ORM for 》的譯文,原文連結:http://ales.jikos.cz/smorm/
【譯】Simple MySQL ORM for C
作者:alesak
c版本Simple MySQL ORM是用python的指令碼完成的,它可以用來串連已經建立的MySQL資料庫,讀取資料庫表所對應的資料結構,當然,也可以通過此資料結構和方法建立表。這些可以讓開發人員使用c語言很方便的更新/修改/刪除資料庫中的資料。
之前,筆者需要在強大的資料庫裡面儲存檢索結構化資料。筆者更傾向於使用MySQL和c語言。但筆者對自己寫的粗糙代碼和互連網上找到的巨費資源的解決方案已經很厭煩了,所以乾脆自己寫了一個。很簡單,很天真,下筆粗糙(python不是筆者的母語,抱歉了)。但相信情人眼裡出西施,筆者想象著讓它更有用一點。還有,關於它的文檔。。。
考慮到這隻是一個技術文章,而不是一個使用手冊。筆者最後取消了此文章提到的項目,所以它有待考驗。不支援MySQL裡頭的一些資料類型。這個項目的起因之一是筆者不喜歡MySQL提供的c api,所以代之以“更時髦”的萬事俱備的api~但,筆者發現它有些地方還不夠好,因為筆者還沒完成。
讓我們開始吧。首先,你必須建立你的資料庫表。筆者更喜歡一下這種方式,因為只有這樣才能更充分使用資料庫。
CREATE DATABASE ex1;CREATE TABLE ex_customer ( id int NOT NULL auto_increment, name char(32), PRIMARY KEY (id));CREATE TABLE ex_item ( customer_id int, itemname char(32));
接下來,我們建立一個簡單的python指令碼db.py:
dbname = "ex1"name = "db"tables = { }
在接下來,讓它執行吧
python rdb.py
當然,比起真正的rock,少點聽覺享受。可能你會問,筆者到底要怎麼串連到資料庫啊?當然,那些只是預設使用者寫的……但看看我們得到的結果。我們可以已經有兩個檔案產生了,分別是:db.h和db.c。前者包含是象徵資料庫表的資料結構聲明和操作這些資料結構的方法;後者包含了方法的定義,接著的是資料初始化的語句。我們來看看:
typedef struct db_ex_customer { int id; char * name;} db_ex_customer;typedef struct db_ex_item { int customer_id; char * itemname;} db_ex_item;
相信沒有進一步解釋這些東西的必要。讓我們使用它們吧!筆者建立了ex1.c檔案。注意:為了更容易讀懂代碼,筆者沒有處理錯誤的傳回值:
#include <db.h>#include <stdio.h>#include <string.h>#include <time.h>int main (int argc, char **argv){int ret;MYSQL global_mysql;MYSQL *m;db_ex_customer *cust1;db_ex_item *item1, *item2;mysql_init (& global_mysql);/* * connect to MySQL as usual */m = mysql_real_connect (& global_mysql, "localhost", "root", "", "ex1", 3036, NULL, 0);/* * pass the MySQL connection to function, that initializes the "ORM" */ret = db_init (& global_mysql);/* * the *__new method creates empty structure */cust1 = db_ex_customer__new ();/* * setting the structure attribute with allocated string, * it will be freed during call of *__free method */cust1->name = strdup ("alesak");/* * this method inserts the structure into according table. * If it has serial field, its value is reflected into structure */ret = db_ex_customer__insert (cust1);item1 = db_ex_item__new ();/* * let's use the serial value from newly inserted customer */item1->customer_id = cust1->id;item1->itemname = strdup ("simple orm");ret = db_ex_item__insert (item1);item2 = db_ex_item__new ();item2->customer_id = cust1->id;item2->itemname = strdup ("advanced orm");ret = db_ex_item__insert (item2);db_ex_customer__free (cust1);db_ex_item__free (item1);db_ex_item__free (item2);return (0);}
編譯下:
cc -I `mysql_config --cflags` ex1.c db.c `mysql_config --libs` -o ex1
運行可執行檔,發現它沒錯。這意味著,它已經一些資料已被儲存。至少如果你讓評價它,筆者會說很優雅。接下來,怎麼去檢索這些資料?假設,我們已經知道資料庫表中記錄的索引值,筆者又建立了ex2.c檔案。
#define _XOPEN_SOURCE 500#include <db.h>#include <stdio.h>#include <string.h>#include <time.h>int main (int argc, char **argv){int ret;MYSQL global_mysql;MYSQL *m;db_ex_customer *cust1;db_ex_item *item1, *item2;mysql_init (& global_mysql);m = mysql_real_connect (& global_mysql, "localhost", "root", "", "ex1", 3036, NULL, 0);ret = db_init (& global_mysql);cust1 = db_ex_customer__get_by_id (3);if (cust1) {fprintf (stdout, "I have customer named \'%s\'\n", cust1->name);db_ex_customer__free (cust1);}return (0);}
跟前邊一樣,編譯,然後執行:
cc -I. `mysql_config --cflags` ex2.c db.c `mysql_config --libs` -o ex2./ex2
最後,筆者不想讓ORM自動建立相關資料的查詢,因為筆者相信它能做的好。(老實說,如果使用預設的MyISAM,它不可能判斷相關資料)。當然,接下來筆者想要建立筆者自己的、超複雜的ex_items表與ex_customer標串連後的SELECT檢索。編輯一下db.py:
dbname = "ex1"name = "db"tables = {"ex_item" :[("get", "get_customer_items",[("INTEGER", "customer_id")], "SELECT ex_item.* FROM ex_item WHERE customer_id = ?")]}
重新執行db.puy指令碼會添加新的db_ex_item__get_customer_items_*方法集。這些方法靈活之處在於,可以增加INTEGER類型的參數,在特定的SQL上開啟遊標:從遊標讀取一行記錄,關閉遊標。我們擴充ex2.c:
#define _XOPEN_SOURCE 500#include <db.h>#include <stdio.h>#include <string.h>#include <time.h>int main (int argc, char **argv){int ret;MYSQL global_mysql;MYSQL *m;db_ex_customer *cust1;db_ex_item *item1, *item2;mysql_init (& global_mysql);m = mysql_real_connect (& global_mysql, "localhost", "root", "", "ex1", 3036, NULL, 0);ret = db_init (& global_mysql);cust1 = db_ex_customer__get_by_id (3);if (cust1) {fprintf (stdout, "I have customer named \'%s\'..\n", cust1->name);db_ex_item__get_customer_items_open (cust1->id);while ((item1 = db_ex_item__get_customer_items_fetch ()) != NULL) {fprintf (stdout, ".. and found his item named \'%s\'\n", item1->itemname);db_ex_item__free (item1);}db_ex_item__get_customer_items_close ();db_ex_customer__free (cust1);}return (0);}
得償所願,它列印的結果:
I have customer named 'alesak'.... and found his item named 'simple orm'.. and found his item named 'advanced orm'
以上,朋友們!這裡是http://ales.jikos.cz/smorm/rdb.py 指令碼。更確切的說,別下載這個破爛東西。但如果你喜歡這個點子,請告訴筆者:alesak#gmail.com。全文完。
感謝作者 @alesak。Simple MySQL ORM for C我沒有親手測試,找時間補上測試篇。另,筆者水平有限,歡迎扶正拍磚。以上。
搗亂 2013-3-22
http://daoluan.net