• protobufnet 学习手记


    因为要做一些数据交换的事情,之前公司都是自己定义一个mdb用来做数据交换的中间文件,现在是想改进一下,在网上找了半天都没找到一个比较好的数据交换的方式,结果就找到了Google的ProtoBuf,有for .net版本的。网上对这个的评价颇高,所以想先拿来研究下。

    先介绍一下我认为有用的一点东西吧。

    看看下面一个例子:

    message Person {
      required string name = 1;
      required int32 id = 2;
      optional string email = 3;
     
      enum PhoneType {
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
      }
     
      message PhoneNumber {
        required string number = 1;
        optional PhoneType type = 2 [default = HOME];
      }
     
      repeated PhoneNumber phone = 4;
    }

    开始定义了一个消息 名字叫Person,然后它有几个字段,一个string类型的name,一个int32类型的id,一个string类型的email,还有一个自定义的类型叫PhoneName,自定义的PhoneNumber的消息的声明也在里面,这个消息有一个string类型的number,还有一个枚举类型的PhoneType,枚举类型的定义也在里面。

    • 1、不要改变已有字段的数字序号.每个消息中的字段后面都有一个等于几,这个数字表示的是这个字段在这个消息中的序号,这个序号在一个消息中必须是唯一的,叫unique numbered tag.而且在一个消息定义好了之后这个序号就不能更改了,不过可以根据需要增加新的字段进去,赋予新的序号,这样的话是可以完全兼容之前的数据类型的.
    • 2、每个字段前面都有一个表示字段的类型的值类型。 .proto文件中支持的值类型有以下几种:double、float、int32、int64、uint32、uint64、sint32、sint64、fixed32、fixed64、sfixed32、sfixed64、bool、string、bytes。比较常用的我觉得就是int32,string和bytes。bytes对应的就是数据库中的二进制字段。
    • 3、在字段类型的前面还有一个用来表示这个字段的规则的。主要是有三个选项:required、optional、repeated。required表示在这个消息中这个字段是必须的,就像数据库中的非空字段一样的,必须要有值。optional表示是可选的,可以有,也可以没有,对应到数据库中的就可空字段。repeated表示这个字段是可以重复的,一个消息是可以有一个或多个这个字段的。 对于repeated类型的字段我有点疑问,为什么它在生成的代理类中是只读的,只有get访问器没有set访问器。对于这种类型的字段我们应该怎么赋值呢?在代理类中repeated类型的字段是一个List。
    • 4、每个字段都可以设置默认值。而且一个.proto文件中也是可以定义多个消息的。消息之间也是可以嵌套的。

    将上面的消息保存为Person.proto,在message外面在给这个消息定义一个package名字,例如 package Person; 这个是用来指定生成的文件的命名空间的,再用下面的命令就可以将这个消息文件.proto编译成一个cs文件,这个叫代理类。可以比较方便快捷的访问我们在.proto文件中定义的一些字段。

    protogen -i:Person.proto -o:Person.cs

    然后再C#中我们就可以像这样使用这个代理类了。

    Person person=new Person();
    person.email="bluesky4485@163.com";
    person.id=4485;
    person.name="bluesky";

    序列化的使用:

    string path = Path.GetTempFileName();
    using (Stream file = File.Create(path))
    {
        Serializer.Serialize(file, person);
        file.Close();
    }

    得到的文件就是序列化之后的文件了。很小的一个二进制文件。

    而反序列化也是很简单的:

    Person cust = new Person();
    using (Stream file = File.OpenRead(path))
    {
        cust = Serializer.Deserialize<Person>(file);
    }

    path就是上面序列化之后的那个文件的路径。反序列化之后得到一个Person对象cust,这个时候就可以通过cust.name、cust.id、cust.email去访问到之前设置的那些值了。真是又方便又简单啊。google已经定义了一个序列化的规则,让我们能更好的使用这个消息所定义的一些字段。

    好,ProtoBuf就说到这,应该有一个大致的了解了吧。再说说我的数据交换的要求吧。将数据库中的一些表,按照一定的规则打包成一个文件,然后再到另一个数据库中导入,感觉比较像报盘系统似的。这个规则也是比较复杂的,表之间的关键字字段各不相同,但是有一定的规律,有的表只能有一条记录,有的表有很多条记录,mdb中的一张表的数据很有可能是先从一个数据库中的好几张表中的一部分字段的值组成的。在我看来由于数据库的异构,导致要生成标准的一个mdb需要做很多操作,而且不够灵活,取数据之类的好多操作都要写死,扩展性不够好。

    简单点说就是有一个标准的mdb模板,现在它就是我的标准文件。我们要从一个数据库中例如是MSSQL中取数据填充mdb中的表,而取的时候有可能会从MSSQL中的多个表中各取部分字段的值存到mdb中的一个表中组成一条记录。假设我们要交换的业务种类不一样的话mdb模板也就不一样,主要是里面的表不一样了。在这种情况下,存在着一种映射,我觉得这样描述比较好,就是MSSQL中的A表中的字段1,字段2、B表中的字段3,字段4,C表中的字段5,字段6,组合成一条记录对应mdb模板中的字段1到字段6.而且有这样一种情况,就是A表和B表的关键字字段值不一样,他们是有一定的联系的,在表D中记录着这2个表中关键字字段值的对应关系。如果按照最原始的方法,你要什么值,我就给你取什么值出来,然后再存进去,这样的话完全就是写死了的,不够灵活,没有扩展性,要是我业务变化了,我的这些所有操作都得重新来写。应该说是只要有一点变化,程序就得改。而且要是增加一类业务也基本上要重新它的所有的存取方法。

    先不说我的需求有没有更好的办法,有的话希望能指点一二。

    我觉得其实是可以做一个映射文件的,告诉我标准文件中的字段取值来源于数据库中的哪个表的哪个字段。想过了,没有比较好的方式去弄这个映射文件,还有就是对于这个映射文件的解析,也没有好的办法。我就是既没有一个好的规则也没有一个好的解析。

    我说说打算用protobuf准备怎么做吧。将标准文件涉及到的所有表都定义为一个消息,每一个表都算是它的一个子消息,每个消息的字段就是表中的一个字段。对于标准文件中必须要有的表,我们将这个表所对应的消息设置为required,对于那些表中有多条记录的就设置为repeated,其他的都可以设置为optional。

    对于一类业务来说,一个序列化之后的文件应该是各不相同的。一个案卷对应一个交换文件。导出的时候序列化。导入的时候接收文件再反序列化回来。然后就又是一个一个的对象可以去拿来直接访问了。对于业务增加的话就相当于值在.proto文件中增加消息。原来的还是可以保持不变。

    由原来写mdb的数据库交互变成了给一堆对象赋值,然后由protobuf序列化去写文件。如果涉及到二进制字段的话序列化之后的大小基本上没什么变化。作为交换文件的话序列化后的文件应该是一个比较好的选择。

    顺便写了一个CodeSmith模板,用来根据数据库中的表生成.proto文件。感觉就跟生成实体类差不多,一个表对应一个消息。

    作者:bluesky4485
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    【bzoj3774】最优选择 网络流最小割
    【bzoj3697】采药人的路径 树的点分治
    【bzoj3576】[Hnoi2014]江南乐 博弈论+SG定理+数学
    【bzoj3451】Tyvj1953 Normal 期望+树的点分治+FFT
    【bzoj2906】颜色 分块
    【bzoj5028】小Z的加油店 扩展裴蜀定理+差分+线段树
    【bzoj2257】[Jsoi2009]瓶子和燃料 扩展裴蜀定理+STL-map
    【bzoj4542】[Hnoi2016]大数 莫队算法
    【bzoj4182】Shopping 树的点分治+dfs序+背包dp
    【bzoj2560】串珠子 状压dp+容斥原理
  • 原文地址:https://www.cnblogs.com/bluesky4485/p/1543133.html
Copyright © 2020-2023  润新知