[其它] 一个简单数据访问接口的设计
dayn9
2007-10-24
我设计一个数据库访问接口,目标是简单易用,STL兼容,类型安全,效率不太差,尽量非侵入。
已实现大部分功能,但我长年困在C/C++世界,视野和经验都很有限,几个地方感觉设计的不太好。 烦请各位老大有空帮看看,指点一二。 我只建立了两个类,数据库类和记录集类。下面是简单示例。 //一个POD类型,要在内存中操作并保存到数据库 struct Student { int num; string name; int age; bool operator==(const Student& s) const { return num == s.num && name == s.name && age == s.age; } }; class3f(Student, num, name, age); //注册Student类型的meta信息 int main() { Sqlite db; db.open("test.db"); //建表 TypeInfo info = typeof(Student()); //获取Student的meta信息 Table tab(info); //根据meta信息创建表结构信息 db.drop(tab); db.create(tab); //向表中填充数据 Student kids[] = { {11, "jiang", 11,}, {12, "kang", 9,}, {13, "cao", 12,}, {14, "ma", 7,}, {15, "tu", 13,}, }; ActiveSet<Student> as1(kids, kids + 5); //数组复制到记录集 db.update(as1); //记录集提交到数据库表 //读取数据到记录集,增删改,之后提交 ActiveSet<Student> as2; db.fill(as2, "age > 10"); Student s1 = {19, "ji", 13}; as2.push_back(s1); as2[3].remove(); Student s2 = as[2]; s2.age += 2; as2[2] = s2; db.update(as2); //只提交有变化的数据 //用stl容器操作数据 vector<Student> v; list<Student> l; map<int64, Student> m; //key是表中的主键,有主键数据才能提交更新 db.fill(v); db.fill(l); db.fill(m); db.update(m); //要提交全部数据,无论变化与否 } |
|
dayn9
2007-10-24
刚才贴的代码,格式惨不忍睹,请教google才学会贴代码,惭愧...
|
|
jimmy_c
2007-10-30
不错啊。有什么问题吗?
|
|
dayn9
2007-10-31
最头痛的一个问题是string的映射。
C++中string是不限长度的,而数据库中的字符串是要设定长度的。而如果string映射成长度无限的text类型,则会损失一部分检索能力和效率。 一个办法是制定字符串的长度。下面是元信息提取的宏,我不知道如何实现指定name的长度而不至于太丑陋。 class3f(Student, num, name, age); //注册Student类型的meta信息 |
|
jimmy_c
2007-10-31
class3f不应该是模板方法么?
定义个 class StringType { private: string _sectionName; int _sectionLength; public: StringType(string sectionName, int sectionLength); }; class TextType { private: string _sectionName; public: StringType(string sectionName); }; 做参数。 然后模板特化。 写成: class3f(Student, num, StringType(name, 256), age); 没有太仔细考虑,不知这样可行不? |
|
jimmy_c
2007-10-31
另一个想法,和上面的问题无关:class3f能不能写成变参的呀?
|
|
dayn9
2007-11-01
class3f是个宏,这是很无奈的选择,也是我觉得实现不好的地方。
这个宏不光要取出类型信息,还要取出类型和成员的字符串名称,这是模板做不到的。类型名称要映射成数据库表名,成员名称要映射成数据库的字段名称。 宏不能可变参数,连重载都不能。所以才这样丑陋: class3f,表示 a class of 3 fields 同样还有class4f ... class10f,够丑陋吧,真的很无奈。 要在C++中实现简单的反射,有更好的办法么? class3f(Student, num, StringType(name, 256), age); 你的这个提议对我很有启发,正在想法实现。 |
|
jimmy_c
2007-11-01
记得boost也有大量类似的代码。
丑陋什么的我的美感神经比较粗,到没觉得什么。不过我是觉得经常碰到table有几十个字段的,这种定义方法,效率就低了。还很可能不够用。所以觉得应该用变参函数好一些。 模板函数而言,如果中间定义一组字段类型类,就像StringType一样,应该也可以处理。不过对于数据库处理而言,其实简单的OO,给它们定义一个基类,应该也足够了,不应该有性能上的问题。 我的想法最终调用大概像这样: classnf<Student>(NullType(), IntType(&Student::num, "num"), StringType(&Student::name, "name", 256), IntType(&Student::age, "age")), NullType()); 两个NullType标记参数表的开始结尾。 如果高兴,可以把IntType(...), StringType(...)定义成宏。 |
|
dayn9
2007-11-05
你提到的也是很现实的问题。
我也曾考虑过,如果表定义实在处理不好,干脆采用RoR中的做法,但如果通过数据定义生成类定义,是不是对OO程序的一种明显的侵入?因为我们的程序和RoR不同,毕竟不是数据主导的。 我还是比较倾向于你的这个提议: class3f(Student, num, StringType(name, 256), age); |
|
jimmy_c
2007-11-05
dayn9 写道 但如果通过数据定义生成类定义,是不是对OO程序的一种明显的侵入?因为我们的程序和RoR不同,毕竟不是数据主导的。
这句话是什么意思?为什么通过数据定义生成类定义就不是OO了呢? 其实template本身就不是OO的范畴,我提到的变参函数完全也不属于OO。但是还是不能理解你的话的意思。 |