-
c语言入门之C++ Builder操纵多媒体数据库
随着计算机软、硬件技术的日益发展,对多媒体信息的处理能力不断增强,利用快速开发工具C++ Builder所具有的强大数据库开发功能,使得对多媒体数据(库)的创建、存、取、显示、播放等控制都非常容易实现。本文将以构建具有5个字段“编号、姓名、像片、声音、活动影像”的数据库为例,根据多媒体数据与数据库本身是否共同存储,介绍两种多媒体数据库处理方法,在这里称为集成法和分离法。
集成法
此方法是将多媒体数据直接存入数据库中,“编号”和“姓名”字段都取ftString字段类型,“像片”字段采用ftGraphic字段类型用于存放BMP文件,“声音”和“活动影像”字段均采用ftBlob字段类型(其他格式的多媒体文件均可以采用这种二进制类型存储),分别用于存放WAV和AVI文件,这样的数据库结构既可以采用C++ Builder提供的“Database Desktop”创建,也可以用下面的代码创建:
TTable *newTable = new TTable(this);
newTable->Active = false;
newTable->DatabaseName = “e:\\mydata”;
newTable->TableName = “example1.db”;
newTable->TableType = ttParadox;
//定义数据表类型
newTable->FieldDefs->Clear();
newTable->FieldDefs->Add(“编号”,ftString,8,false); //定义字段、类型、长度等
newTable->FieldDefs->Add(“姓名”,ftString,8,false);
newTable->FieldDefs->Add(“像片”,ftGraphic,0,false);
newTable->FieldDefs->Add(“声音”,ftBlob,0,false);
newTable->FieldDefs->Add(“数字电影”,ftBlob,0,false);
newTable->CreateTable(); //创建数据表
delete newTable;
由于要编程实现往数据库中添加记录的功能,因此假定在数据库程序设计阶段数据表example1
.db已经建好,同时假定所需要的多媒体文件均存放于e:\mydata\media路径之下。
所要完成的程序的功能界面如图1所示:
图 1 操作界面
点击“打开数据库”按钮将打开库文件example1.db并显示原有记录的相应信息。点击“增加记录”按钮将追加新的记录,通过数据导航按钮进行记录的移动、修改等操作,在每一时刻,点击“听听声”按钮可以听到当前记录所对应的声音,点击“看看影”按钮可以看到当前记录对应的活动影像。这个应用已具备一个多媒体数据库应用系统的基本功能,以下是主要设计步骤:
1. 组件设置
向窗体增加一个TTable组件Table1,一个TDataSource组件DataSource1,两个TDBEdit组件DBEdit1和DBEdit2,一个TDBImage组件DBImage1,一个TDBNavigator组件DBNavigator1,一个TMediaPlayer组件MediaPlayer1,一个TOleContainer组件OleContainer1,四个TButton组件和三个TLable组件。这些组件需要设置的部分属性如下表:
作者:
来自:计算机世界网
注: 表中标记“▲”的几个属性表示只有数据表example1.db已经存在,才能在设计阶段进行设置。
2. 创建字段变量
双击窗体的Table1组件,在弹出的 “Form1->Table1” 小窗口的空白处单击鼠标右键,选择“Add Fields...”菜单命令,然后选中“像片、声音、活动影像”三个字段,点击OK按钮。回到“Form1->Table1”小窗口,选中“图片”,将其Name属性修改为Table1BMPField。类似地将“声音”和“活动影像”的Name属性分别修改为Table1WAVField和Table1AVIField,这样就创建了对应的字段变量,利用它们就可以动态地向相应字段中存入多媒体数据了(如果数据表example1.db不存在,应该选择“New Fields...”菜单命令创建,这样做必须创建所有的字段,较为麻烦)。
3. 代码设计
“打开数据库”按钮的OnClick事件过程代码如下:
void __fastcall TForm1::Button1Click(TObject *Sender)
{ Table1->DatabaseName = “e:\\mydata”;
Table1->TableName = “example1.db”;
Table1->Active = true; //打开数据表
}
在“增加记录”按钮的OnClick的事件过程中输入代码:
void __fastcall TForm1::Button2Click(TObject *Sender)
{ Table1->DatabaseName = “e:\\mydata”;
Table1->TableName = “example1.db”;
Table1->Active = true;
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010521”,“刘德友”)));
//增加一条记录
Table1->Edit( ); //进入编辑状态
Table1BMPField->LoadFromFile(“\\media\\ldy.bmp”);
//将图片文件载入像片字段
Table1WAVField->LoadFromFile(“\\media\\ldy.wav”);
//将声音文件载入声音字段
Table1AVIField->LoadFromFile(“\\media\\ldy.avi”);
//将电影文件载入活动影像字段
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010522”,“王英”)));
//增加第二条记录
Table1->Edit( );
Table1BMPField->LoadFromFile(“\\media\\wy.bmp”);
Table1WAVField->LoadFromFile(“\\media\\wy.wav”);
Table1AVIField->LoadFromFile(“\\media\\wy.avi”);
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010523”,“张雪花”)));
//添加第三条记录
Table1->Edit( );
Table1BMPField->LoadFromFile(“\\media\\zxh.bmp”);
Table1WAVField->LoadFromFile(“\\media\\zxh.wav”);
Table1AVIField->LoadFromFile(“\\media\\zxh.avi”);
}
用类似的语句可以添加多条记录。显然,若需要其他格式的多媒体数据文件也可用此法,作为二进制文件将其存入数据库。如果利用TOpenDialog组件则能够在运行过程中实现“动态”加载多媒体数据文件到相应字段。
按钮“听听声”的OnClick事件过程的代码如下:
void __fastcall TForm1::Button3Click(TObject *Sender)
{ AnsiString waveName = “temp.wav”;
Table1WAVField-> SaveToFile(waveName);
//存成临时文件
Sleep(50); //作为缓冲,暂停50毫秒
MediaPlayer1->FileName = waveName;
MediaPlayer1->Open();
MediaPlayer1->Play();
}
按钮“看看影”的OnClick事件过程的代码如下:
void __fastcall TForm1::Button4Click(TObject *Sender)
{ AnsiString aviName = “temp.avi”;
Table1AVIField->SaveToFile(aviName);
Sleep(50);
OleContainer1->CreateLinkToFile(aviName,false);
OleContainer1->DoVerb(ovPrimary);
}
注意这里使用TOleContainer1组件实现AVI播放,当然也可以用MediaPlayer1组件进行播放,此处只是提供了一种方法:利用软件的OLE技术对一些特殊格式的多媒体数据文件采用TOleContainer处理,例如DOC、PSD、DWG、SWF等,只要目标计算机安装了该软件的服务程序(想知道计算机支持哪些格式媒体文件只要在Word软件中查看“插入——>对象...”菜单便知),笔者利用此技术成功地实现了Flash动画存储和播放(已装有Flash 5)。当然也可使用第三方开发的组件或控件,C++ Builder也支持OCX控件,例如利用MP3Play控件实现MP3的播放。
至此,一个小型的多媒体数据库系统用“集成法”创建完成。
分离法
这种方法就是将多媒体数据与数据库分开存放。在数据库中相应的字符字段只存放该多媒体数据的文件名,它是数据库与数据之间的“接口”。这种情况下数据库结构可以在运行中动态创建,因此可在功能界面上(功能界面上的其他部分与图1完全相同)再增加一个按钮“创建数据库结构”并在其OnClick事件过程置入如下代码:
void __fastcall TForm1::Button5Click(TObject *Sender)
{ TTable *newTable = new TTable(this);
newTable->Active = false;
newTable->DatabaseName =“e:\\mydata”;
newTable->TableName = “example2.db”;
newTable->TableType = ttParadox;
newTable->FieldDefs->Clear();
newTable->FieldDefs->Add(“编号”,ftString,8,false);
//字段均为字符型
newTable->FieldDefs->Add(“姓名”,ftString,8,false);
newTable->FieldDefs->Add(“像片”,ftString,12,false);
newTable->FieldDefs->Add(“声音”,ftString,12,false);
newTable->FieldDefs->Add(“活动影像”,ftString,12,false);
newTable->CreateTable();
delete newTable;
}
由于允许动态创建库结构,组件Table1的DatabaseName属性和DBEdit1、DBEdit2的DataField属性用代码进行设置。因为“像片”字段存放的只是其文件名,所以组件DBImage1用Image1组件代替。这时,只需将“打开数据库”按钮的OnClick事件过程修改为:
void __fastcall TForm1::Button1Click(TObject *Sender)
{ Table1->DatabaseName = “e:\\mydata”;
Table1->TableName = “example2.db”;
DBEdit1->DataField = “编号”;
DBEdit2->DataField = “姓名”;
Table1->Active = true;
Image1->Picture->LoadFromFile(Table1->DatabaseName + “\\media\\” + Table1->FieldByName(“像片”)->AsString);
}
将“增加记录”按钮的OnClick事件过程修改为:
void __fastcall TForm1::Button2Click(TObject *Sender)
{ Table1->Active = false;
Table1->DatabaseName = “e:\\mydata”;
Table1->TableName = “example2.db”;
Table1->Active = true;
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010521”,“刘德友”,“ldy.bmp”,“ldy.wav”,“ldy.avi”)));
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010522”,“王英”,“wy.bmp”,“wy
.wav”,“wy.avi”)));
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010523”,“张学华”,“zxh.bmp”,“zxh.wav”,“zxh.avi”)));
Table1->First();
//记录指针移到数据表首条记录
Image1->Picture->LoadFromFile(Table1->DatabaseName + “\\media\\”+Table1->FieldByName(“像片”)->AsString);
}
将“听听声”按钮的OnClick事件过程修改为:
void __fastcall TForm1::Button3Click(TObject *Sender)
{ AnsiString wavName = Table1->DatabaseName + “\\media\\” + Table1->FieldByName(“声音”)->AsString;
MediaPlayer1->FileName = wavName;
MediaPlayer1->Open();
MediaPlayer1->Play();
}
将“看看影”按钮的OnClick事件过程修改为:
void __fastcall TForm1::Button4Click(TObject *Sender)
{ AnsiString aviName = Table1->DatabaseName + “\\media\\” + Table1->FieldByName(“活动影像”)->AsString;
OleContainer1->CreateLinkToFile(aviName,false);
OleContainer1->DoVerb(ovPrimary);
}
为了使操作界面上显示的像片能随记录指针的移动而改变,可以添加组件DBNavigator1的OnClick事件,其过程代码只有一条语句:
void __fastcall TForm1::DBNavigator1Click(TObject *Sender, TNavigateBtn Button)
{ Image1->Picture->LoadFromFile(Table1->DatabaseName + “\\media\\” + Table1->FieldByName(“像片”)->AsString);
}
至此,一个小型的多媒体数据库系统用“分离法”创建完成。
小 结
以上介绍了多媒体数据从创建、存入,到读取、显示、播放等两种不同的控制方法,这两种处理方式各有优劣。若多媒体数据与数据库共同存储,数据便于管理,整个数据库系统只有一个数据库文件,但它的缺点是数据库文件会变得非常之大,使应用系统读取的运行效率降低; 若多媒体数据与数据库分开存储,其缺点是文件数量较多,维护、管理不太方便,但它的优点是数据库文件较小,数据库打开和应用系统读取的运行效率大大提高。
一般的原则是,如果多媒体数据的尺寸较小并且又有专门的数据库组件可与之关联,如职工的照片BMP文件可用组件TDBImage、格式化文档RTF文件可用组件TDBRichEdit等,这时可以采用“集成法”将数据直接存入数据库; 若多媒体数据的尺寸较大,如音频、视频等,可将数据与数据库分开存储,在数据库中只保留多媒体数据的文件名,是一种“链接”的方式,这样做有一定的灵活性,比如想修改某条记录的信息,只需直接修改数据文件,而不必打开数据库。
集成法
此方法是将多媒体数据直接存入数据库中,“编号”和“姓名”字段都取ftString字段类型,“像片”字段采用ftGraphic字段类型用于存放BMP文件,“声音”和“活动影像”字段均采用ftBlob字段类型(其他格式的多媒体文件均可以采用这种二进制类型存储),分别用于存放WAV和AVI文件,这样的数据库结构既可以采用C++ Builder提供的“Database Desktop”创建,也可以用下面的代码创建:
TTable *newTable = new TTable(this);
newTable->Active = false;
newTable->DatabaseName = “e:\\mydata”;
newTable->TableName = “example1.db”;
newTable->TableType = ttParadox;
//定义数据表类型
newTable->FieldDefs->Clear();
newTable->FieldDefs->Add(“编号”,ftString,8,false); //定义字段、类型、长度等
newTable->FieldDefs->Add(“姓名”,ftString,8,false);
newTable->FieldDefs->Add(“像片”,ftGraphic,0,false);
newTable->FieldDefs->Add(“声音”,ftBlob,0,false);
newTable->FieldDefs->Add(“数字电影”,ftBlob,0,false);
newTable->CreateTable(); //创建数据表
delete newTable;
由于要编程实现往数据库中添加记录的功能,因此假定在数据库程序设计阶段数据表example1
.db已经建好,同时假定所需要的多媒体文件均存放于e:\mydata\media路径之下。
所要完成的程序的功能界面如图1所示:
图 1 操作界面
点击“打开数据库”按钮将打开库文件example1.db并显示原有记录的相应信息。点击“增加记录”按钮将追加新的记录,通过数据导航按钮进行记录的移动、修改等操作,在每一时刻,点击“听听声”按钮可以听到当前记录所对应的声音,点击“看看影”按钮可以看到当前记录对应的活动影像。这个应用已具备一个多媒体数据库应用系统的基本功能,以下是主要设计步骤:
1. 组件设置
向窗体增加一个TTable组件Table1,一个TDataSource组件DataSource1,两个TDBEdit组件DBEdit1和DBEdit2,一个TDBImage组件DBImage1,一个TDBNavigator组件DBNavigator1,一个TMediaPlayer组件MediaPlayer1,一个TOleContainer组件OleContainer1,四个TButton组件和三个TLable组件。这些组件需要设置的部分属性如下表:
作者:
来自:计算机世界网
注: 表中标记“▲”的几个属性表示只有数据表example1.db已经存在,才能在设计阶段进行设置。
2. 创建字段变量
双击窗体的Table1组件,在弹出的 “Form1->Table1” 小窗口的空白处单击鼠标右键,选择“Add Fields...”菜单命令,然后选中“像片、声音、活动影像”三个字段,点击OK按钮。回到“Form1->Table1”小窗口,选中“图片”,将其Name属性修改为Table1BMPField。类似地将“声音”和“活动影像”的Name属性分别修改为Table1WAVField和Table1AVIField,这样就创建了对应的字段变量,利用它们就可以动态地向相应字段中存入多媒体数据了(如果数据表example1.db不存在,应该选择“New Fields...”菜单命令创建,这样做必须创建所有的字段,较为麻烦)。
3. 代码设计
“打开数据库”按钮的OnClick事件过程代码如下:
void __fastcall TForm1::Button1Click(TObject *Sender)
{ Table1->DatabaseName = “e:\\mydata”;
Table1->TableName = “example1.db”;
Table1->Active = true; //打开数据表
}
在“增加记录”按钮的OnClick的事件过程中输入代码:
void __fastcall TForm1::Button2Click(TObject *Sender)
{ Table1->DatabaseName = “e:\\mydata”;
Table1->TableName = “example1.db”;
Table1->Active = true;
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010521”,“刘德友”)));
//增加一条记录
Table1->Edit( ); //进入编辑状态
Table1BMPField->LoadFromFile(“\\media\\ldy.bmp”);
//将图片文件载入像片字段
Table1WAVField->LoadFromFile(“\\media\\ldy.wav”);
//将声音文件载入声音字段
Table1AVIField->LoadFromFile(“\\media\\ldy.avi”);
//将电影文件载入活动影像字段
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010522”,“王英”)));
//增加第二条记录
Table1->Edit( );
Table1BMPField->LoadFromFile(“\\media\\wy.bmp”);
Table1WAVField->LoadFromFile(“\\media\\wy.wav”);
Table1AVIField->LoadFromFile(“\\media\\wy.avi”);
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010523”,“张雪花”)));
//添加第三条记录
Table1->Edit( );
Table1BMPField->LoadFromFile(“\\media\\zxh.bmp”);
Table1WAVField->LoadFromFile(“\\media\\zxh.wav”);
Table1AVIField->LoadFromFile(“\\media\\zxh.avi”);
}
用类似的语句可以添加多条记录。显然,若需要其他格式的多媒体数据文件也可用此法,作为二进制文件将其存入数据库。如果利用TOpenDialog组件则能够在运行过程中实现“动态”加载多媒体数据文件到相应字段。
按钮“听听声”的OnClick事件过程的代码如下:
void __fastcall TForm1::Button3Click(TObject *Sender)
{ AnsiString waveName = “temp.wav”;
Table1WAVField-> SaveToFile(waveName);
//存成临时文件
Sleep(50); //作为缓冲,暂停50毫秒
MediaPlayer1->FileName = waveName;
MediaPlayer1->Open();
MediaPlayer1->Play();
}
按钮“看看影”的OnClick事件过程的代码如下:
void __fastcall TForm1::Button4Click(TObject *Sender)
{ AnsiString aviName = “temp.avi”;
Table1AVIField->SaveToFile(aviName);
Sleep(50);
OleContainer1->CreateLinkToFile(aviName,false);
OleContainer1->DoVerb(ovPrimary);
}
注意这里使用TOleContainer1组件实现AVI播放,当然也可以用MediaPlayer1组件进行播放,此处只是提供了一种方法:利用软件的OLE技术对一些特殊格式的多媒体数据文件采用TOleContainer处理,例如DOC、PSD、DWG、SWF等,只要目标计算机安装了该软件的服务程序(想知道计算机支持哪些格式媒体文件只要在Word软件中查看“插入——>对象...”菜单便知),笔者利用此技术成功地实现了Flash动画存储和播放(已装有Flash 5)。当然也可使用第三方开发的组件或控件,C++ Builder也支持OCX控件,例如利用MP3Play控件实现MP3的播放。
至此,一个小型的多媒体数据库系统用“集成法”创建完成。
分离法
这种方法就是将多媒体数据与数据库分开存放。在数据库中相应的字符字段只存放该多媒体数据的文件名,它是数据库与数据之间的“接口”。这种情况下数据库结构可以在运行中动态创建,因此可在功能界面上(功能界面上的其他部分与图1完全相同)再增加一个按钮“创建数据库结构”并在其OnClick事件过程置入如下代码:
void __fastcall TForm1::Button5Click(TObject *Sender)
{ TTable *newTable = new TTable(this);
newTable->Active = false;
newTable->DatabaseName =“e:\\mydata”;
newTable->TableName = “example2.db”;
newTable->TableType = ttParadox;
newTable->FieldDefs->Clear();
newTable->FieldDefs->Add(“编号”,ftString,8,false);
//字段均为字符型
newTable->FieldDefs->Add(“姓名”,ftString,8,false);
newTable->FieldDefs->Add(“像片”,ftString,12,false);
newTable->FieldDefs->Add(“声音”,ftString,12,false);
newTable->FieldDefs->Add(“活动影像”,ftString,12,false);
newTable->CreateTable();
delete newTable;
}
由于允许动态创建库结构,组件Table1的DatabaseName属性和DBEdit1、DBEdit2的DataField属性用代码进行设置。因为“像片”字段存放的只是其文件名,所以组件DBImage1用Image1组件代替。这时,只需将“打开数据库”按钮的OnClick事件过程修改为:
void __fastcall TForm1::Button1Click(TObject *Sender)
{ Table1->DatabaseName = “e:\\mydata”;
Table1->TableName = “example2.db”;
DBEdit1->DataField = “编号”;
DBEdit2->DataField = “姓名”;
Table1->Active = true;
Image1->Picture->LoadFromFile(Table1->DatabaseName + “\\media\\” + Table1->FieldByName(“像片”)->AsString);
}
将“增加记录”按钮的OnClick事件过程修改为:
void __fastcall TForm1::Button2Click(TObject *Sender)
{ Table1->Active = false;
Table1->DatabaseName = “e:\\mydata”;
Table1->TableName = “example2.db”;
Table1->Active = true;
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010521”,“刘德友”,“ldy.bmp”,“ldy.wav”,“ldy.avi”)));
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010522”,“王英”,“wy.bmp”,“wy
.wav”,“wy.avi”)));
Table1->AppendRecord(OPENARRAY(TVarRec,(“20010523”,“张学华”,“zxh.bmp”,“zxh.wav”,“zxh.avi”)));
Table1->First();
//记录指针移到数据表首条记录
Image1->Picture->LoadFromFile(Table1->DatabaseName + “\\media\\”+Table1->FieldByName(“像片”)->AsString);
}
将“听听声”按钮的OnClick事件过程修改为:
void __fastcall TForm1::Button3Click(TObject *Sender)
{ AnsiString wavName = Table1->DatabaseName + “\\media\\” + Table1->FieldByName(“声音”)->AsString;
MediaPlayer1->FileName = wavName;
MediaPlayer1->Open();
MediaPlayer1->Play();
}
将“看看影”按钮的OnClick事件过程修改为:
void __fastcall TForm1::Button4Click(TObject *Sender)
{ AnsiString aviName = Table1->DatabaseName + “\\media\\” + Table1->FieldByName(“活动影像”)->AsString;
OleContainer1->CreateLinkToFile(aviName,false);
OleContainer1->DoVerb(ovPrimary);
}
为了使操作界面上显示的像片能随记录指针的移动而改变,可以添加组件DBNavigator1的OnClick事件,其过程代码只有一条语句:
void __fastcall TForm1::DBNavigator1Click(TObject *Sender, TNavigateBtn Button)
{ Image1->Picture->LoadFromFile(Table1->DatabaseName + “\\media\\” + Table1->FieldByName(“像片”)->AsString);
}
至此,一个小型的多媒体数据库系统用“分离法”创建完成。
小 结
以上介绍了多媒体数据从创建、存入,到读取、显示、播放等两种不同的控制方法,这两种处理方式各有优劣。若多媒体数据与数据库共同存储,数据便于管理,整个数据库系统只有一个数据库文件,但它的缺点是数据库文件会变得非常之大,使应用系统读取的运行效率降低; 若多媒体数据与数据库分开存储,其缺点是文件数量较多,维护、管理不太方便,但它的优点是数据库文件较小,数据库打开和应用系统读取的运行效率大大提高。
一般的原则是,如果多媒体数据的尺寸较小并且又有专门的数据库组件可与之关联,如职工的照片BMP文件可用组件TDBImage、格式化文档RTF文件可用组件TDBRichEdit等,这时可以采用“集成法”将数据直接存入数据库; 若多媒体数据的尺寸较大,如音频、视频等,可将数据与数据库分开存储,在数据库中只保留多媒体数据的文件名,是一种“链接”的方式,这样做有一定的灵活性,比如想修改某条记录的信息,只需直接修改数据文件,而不必打开数据库。
最新更新
Objective-C语法之代码块(block)的使用
VB.NET eBook
Add-in and Automation Development In VB.NET 2003 (F
Add-in and Automation Development In VB.NET 2003 (8
Add-in and Automation Development in VB.NET 2003 (6
Add-in and Automation Development In VB.NET 2003 (5
AddIn Automation Development In VB.NET 2003 (4)
AddIn And Automation Development In VB.NET 2003 (2)
Addin and Automation Development In VB.NET 2003 (3)
AddIn And Automation Development In VB.NET 2003 (1)
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
武装你的WEBAPI-OData入门
武装你的WEBAPI-OData便捷查询
武装你的WEBAPI-OData分页查询
武装你的WEBAPI-OData资源更新Delta
5. 武装你的WEBAPI-OData使用Endpoint 05-09
武装你的WEBAPI-OData之API版本管理
武装你的WEBAPI-OData常见问题
武装你的WEBAPI-OData聚合查询
OData WebAPI实践-OData与EDM
OData WebAPI实践-Non-EDM模式