protobuf + Mysql+实现消息反射查询返回数据

根据 type name 创建 Message ,利用GetReflection()反射填充

  • DescriptorPool::generated_pool() 找到一个DescriptorPool对象,它包含了程序编译的时候所链接的全部 protobuf Message types
  • DescriptorPool::FindMessageTypeByName() 根据 type name 查找 Descriptor
  • 再用 MessageFactory::generated_factory() 找到 MessageFactory对象,它能创建程序编译的时候所链接的全部 protobuf Message types
  • 然后,用 MessageFactory::GetPrototype() 找到具体 Message Typedefault instance
  • 最后,用 prototype->New() 创建对象。
message QueryAccount
{    
    // in
    required string SQL = 1;
    
    // out
    optional int64 id = 2;
}


 void ReflectionFill( google::protobuf::Message* Msg, const google::protobuf::Descriptor* MsgDescriptor, mysqlpp::Row& RowData )
{
     using namespace google::protobuf;
  
      // 遍历所有消息成员
     for ( size_t i = 0;i < MsgDescriptor->field_count();i++ )
    {        
        const FieldDescriptor* EachField = MsgDescriptor->field( i );
  // 这里假定optinal的是返回值
       if ( !EachField->is_optional() )
            continue;
       // sql的列
       std::string FieldName = EachField->name(); 
        // 返回的CPP类型
       switch ( EachField->cpp_type() )
       {
          case FieldDescriptor::CPPTYPE_STRING:
           {
             std::string Result  = RowData[FieldName.c_str()];
              Msg->GetReflection()->SetString( Msg, EachField, Result );
             }
             break;
          case FieldDescriptor::CPPTYPE_INT64:
            {
               // 从列取值
                __int64 Result = RowData[FieldName.c_str()];

                // 设置消息
              Msg->GetReflection()->SetInt64( Msg, EachField, Result );
            }
           break;
        }
 
    }
 }
    
 void ParseMessage( mysqlpp::Connection& SQLConnection, const char* ProtoType, void* Data, size_t Size )
 {
     // 转载请注明来自 战魂小筑http://www.cppblog.com/sunicdavy
    using namespace google::protobuf;
 
    Message* Msg = NULL;
  
    // 通过类型字符串查出消息类型信息
    const Descriptor* MsgDescriptor = DescriptorPool::generated_pool()->FindMessageTypeByName(ProtoType);
    if (MsgDescriptor == NULL )
        return;
 
    // 取消息原型
     const Message* MsgPrototype = MessageFactory::generated_factory()->GetPrototype(MsgDescriptor);
    if (MsgPrototype == NULL )
         return;

    // 不能用原型消息哦,要新的
     Msg = MsgPrototype->New();

   // 解析数据
     Msg->ParseFromArray( Data, Size );
 
  // 查找SQL指令
   const FieldDescriptor* SQLField = MsgDescriptor->FindFieldByName("SQL");
    if ( SQLField == NULL )
        return;
 
    // 使用反射查出值
    std::string SQLCmd = Msg->GetReflection()->GetString( *Msg, SQLField );

   // 进行SQL查询
     mysqlpp::Query query = SQLConnection.query( SQLCmd.c_str() );

   // 确认查询有效
    mysqlpp::StoreQueryResult res = query.store();

   if (!res)
       return;
 
    // 这里只取第一个消息
    mysqlpp::Row RowData = *res.begin();

   // 反射填充消息
   ReflectionFill( Msg, MsgDescriptor, RowData );
 
   // 测试返回数据
     dbsvc::QueryAccount* qamsg = dynamic_cast<dbsvc::QueryAccount*>( Msg );
   __int64 i = qamsg->id();

   delete Msg;
 }
 

 int main(int argc, char* argv[])
{    
     mysqlpp::Connection con(false);
  
     con.set_option(new mysqlpp::SetCharsetNameOption("gbk"));


     if (!con.connect("testdb", "localhost", "root", "123"))
       {
        return -1;
       }
     else
       {
        dbsvc::QueryAccount Msg;
       Msg.set_sql("select id from account where username = 'hello'");
         std::string s;
        Msg.SerializeToString( &s );

        ParseMessage( con, "dbsvc.QueryAccount", (void*)s.data(), s.size() );
        }
    google::protobuf::ShutdownProtobufLibrary();
 }

参考

1、http://www.cppblog.com/sunicdavy/archive/2011/12/14/162115.html
2、https://www.cnblogs.com/Solstice/archive/2011/04/03/2004458.html
3、https://my.oschina.net/cqcbw/blog/3048689

猜你喜欢

转载自blog.csdn.net/JMW1407/article/details/107665041