c++中数据表如何转成业务实体--map和结构体的相互转换
应用场景:如何把数据库表中的一行转换成一个业务实体结构体,c#和java中都有实体框架,表到实体的转换很方便,c++中缺少这些框架,但是有一些折中的办法去做。其实问题的本质是:map如何转成结构体。
问题:map的字段和结构体字段一一对应时,如何把map中字段对应的值付给结构体中相同名称字段?
有点麻烦的地方:如何让结构体去在map中查找相应的字段值,一种办法是通过手写的办法,把每个字段名称写成常量字符串,然后去map中查找,找到后,再给该字段赋值,这个办法是可以的,但是重复性的硬编码了很多字段名称,代码也比较丑陋。
一个比较好的办法是通过一个宏和一个模板函数去赋值比较好。
这是我们的结构体 #define VarName(x) #x //字段转成名称的宏
struct TestInfo { int ID; int KPIID; int Code; int V1; int V2; int V3; void Init() { memset(this, 0, sizeof(TestInfo)); } void Make(SweetDB::Row& row) { Init(); GetValue(row, VarName(ID), ID); GetValue(row, VarName(KPIID), KPIID); GetValue(row, VarName(Code), Code); GetValue(row, VarName(V1), V1); GetValue(row, VarName(V2), V2); GetValue(row, VarName(V3), V3); } void MakeToRow(SweetDB::Row& row) { row[VarName(ID)] = ID; row[VarName(KPIID)] = KPIID; } template<typename T> static bool GetValue(SweetDB::Row& row, const char* name, T& t) { auto it = row.find(name); if (it == row.end()) return false; t = get<T>(it->second); return true; } };
测试代码:
typedef boost::variant<double, int, string>Value; typedef unordered_map<const char*, Value> Row; TestInfoResult TestDoublePointer() { SweetDB::Row row = { {"ID", 1}, { "KPIID", 2 }, { "Code", 2 } }; TestInfo t; t.Make(row); //把map中对应的字段值赋给t SweetDB::Row row1; t.MakeToRow(row1); //把t的字段值赋给map }
最后我们看到map to struct成功了,struct to map也成功了。
优点是不用硬编码字段名称,缺点是,每个字段的赋值还是要编码,这个工作量还是没省,如果是c#语言直接就通过反射搞定,不需要这么绕弯子了,c++语言就没办法,只能自己发明轮子了。也许大家还有更好的办法,可以一起探讨一下。
也许c++ ORM框架大体可以按这个思路去做吧。
一点梦想:尽自己一份力,让c++的世界变得更美好!