酒店点餐系统开发详解(四)

——数据库模块设计

在本系统中每个模块与数据库的一系列查询、插入、删除等操作是通过类CDatabaseOperation进行的,所有的数据库操作都封装在这个类中。数据库功能的封装增加了模块的独立性和复用性,便于进行二次开发和软件的修改。

本系统采用ADO对象进行数据库操作,故应在stdafx.h中添加“#import "c:/program files/common files/system/ado/msado15.dll" no_namespace rename("EOF","_EOF")”(不包括引号),每个模块刚启动并连接数据库的操作如下:

BOOL CCookTerminalApp::InitInstance()

{

……

AfxEnableControlContainer();

::CoInitialize(NULL);//初始化com环境

//网络连接初始化

AfxSocketInit(NULL);

//数据库连接

ConnectSQLServer();

……

}

//连接数据库

void CCookTerminalApp::ConnectSQLServer()

{

CString IP,User,Passwd;

int Port;

GetPrivateProfileString("SQLServer","IP","local",IP.GetBuffer(20),20,".//default.ini");

IP.ReleaseBuffer();

GetPrivateProfileString("SQLServer","User","sa",User.GetBuffer(20),20,".//default.ini");

User.ReleaseBuffer();

GetPrivateProfileString("SQLServer","Passwd","",Passwd.GetBuffer(20),20,".//default.ini");

Passwd.ReleaseBuffer();

Port = GetPrivateProfileInt("SQLServer","Port",1433,".//default.ini");

//数据库连接初始化

m_DbOp.CreateInstance();

if(IP == "local")

m_DbOp.OpenLocalDatabase("DishesSystem");

else{

CString str;

str.Format("%s,%d",IP,Port);

m_DbOp.OpenRemoteDatabase(str,"DishesSystem",User,Passwd);

}

}

类CDatabaseOperation的具体接口及实现如下:

1、创建实例

void CDatabaseOperation::CreateInstance()

{

cnn.CreateInstance(__uuidof(Connection));

rst.CreateInstance(__uuidof(Recordset));

}

2、打开本地数据库

void CDatabaseOperation::OpenLocalDatabase(CString basename)

{

CString str;

str.Format(_T("Provider=SQLOLEDB.1;Data Source=(local);Initial Catalog=%s;Integrated Security=SSPI"),basename);

cnn->ConnectionString = (_bstr_t)str;

try{

cnn->Open(L"",L"",L"",adCmdUnspecified);

}catch(_com_error &e){

CatchError(e);

}

}

3、打开远程数据库

void CDatabaseOperation::OpenRemoteDatabase(CString source, CString basename, CString user, CString pwd)

{

CString str;

str.Format(_T("Provider=SQLOLEDB.1;Data Source=%s;Network Library=DBMSSOCN;Initial Catalog=%s;User ID=%s;Password=%s"),source,basename,user,pwd);

cnn->ConnectionString = (_bstr_t)str;

try{

cnn->Open(L"",L"",L"",adCmdUnspecified);

}catch(_com_error &e){

CatchError(e);

}

}

4、打开记录集

BOOL CDatabaseOperation::OpenRecordset(CString sqlstatement)

{

CloseRecordset();

try{

rst->CursorLocation = adUseClient;

rst->Open((_variant_t)sqlstatement,_variant_t((IDispatch *)cnn,true),adOpenDynamic,adLockPessimistic,adCmdText);

}catch(_com_error &e){

// CatchError(e);

return FALSE;

}

return TRUE;

}

5、关闭记录集

void CDatabaseOperation::CloseRecordset()

{

if(rst->State)

rst->Close();

}

6、返回记录集

_RecordsetPtr CDatabaseOperation::GetRecordset(CString sqlstatement)

{

_RecordsetPtr rst;

rst.CreateInstance(__uuidof(Recordset));

try{

rst->CursorLocation = adUseClient;

rst->Open((_variant_t)sqlstatement,_variant_t((IDispatch *)cnn,true),adOpenDynamic,adLockPessimistic,adCmdText);

}catch(_com_error &e){

// CatchError(e);

return NULL;

}

return rst;

}

7、插入新数据

BOOL CDatabaseOperation::InsertItem(CString sqlstatement)

{

try{

cnn->Execute((_bstr_t)sqlstatement,NULL,adCmdText);

}catch(_com_error &e){

CatchError(e);

return FALSE;

}

return TRUE;

}

8、修改数据

BOOL CDatabaseOperation::UpdateItem(CString sqlstatement)

{

try{

cnn->Execute((_bstr_t)sqlstatement,NULL,adCmdText);

}catch(_com_error &e){

CatchError(e);

return FALSE;

}

return TRUE;

}

9、删除数据

BOOL CDatabaseOperation::DeleteItem(CString sqlstatement)

{

try{

cnn->Execute((_bstr_t)sqlstatement,NULL,adCmdText);

}catch(_com_error &e){

CatchError(e);

return FALSE;

}

return TRUE;

}

10、返回属性值

CString CDatabaseOperation::GetAttrValues(CString attr)

{

_variant_t vt;

CString values;

if(rst->_EOF || rst->BOF)

return "";

try{

vt = rst->GetCollect((_variant_t)attr);

}catch(_com_error &e){

CatchError(e);

return "";

}

values = (LPCSTR)_bstr_t(vt);

return values;

}

11、读取数据库图片数据

char *CDatabaseOperation::ReadPictureData(CString sqlstatement, CString attrName)

{

_RecordsetPtr temp_rst;

char *buf = NULL;

temp_rst.CreateInstance(__uuidof(Recordset));

try{

temp_rst->Open((_variant_t)sqlstatement,_variant_t((IDispatch *)cnn,true),adOpenDynamic,adLockPessimistic,adCmdText);

}catch(_com_error &e){

CatchError(e);

return NULL;

}

long lDataSize;

try{

lDataSize = temp_rst->GetFields()->GetItem((_variant_t)attrName)->ActualSize;

}catch(_com_error &e){

CatchError(e);

return NULL;

}

if(lDataSize > 0)

{

_variant_t varBLOB;

try{

varBLOB = temp_rst->GetFields()->GetItem((_variant_t)attrName)->GetChunk(lDataSize);

}catch(_com_error &e){

CatchError(e);

return NULL;

}

if(varBLOB.vt == (VT_ARRAY | VT_UI1))

{

if(buf = new char[lDataSize+1]) ///重新分配必要的存储空间

{

char *pBuf = NULL;

SafeArrayAccessData(varBLOB.parray,(void **)&pBuf);

memcpy(buf,pBuf,lDataSize); ///复制数据到缓冲区

SafeArrayUnaccessData (varBLOB.parray);

}

}

}

return buf;

}

12、保存图片到数据库

BOOL CDatabaseOperation::SavePicture(CString sqlstatement, CString attrName, char *buf, long len)

{

if(buf == NULL)

return TRUE;

char *pBuf = buf;

VARIANT varBLOB;

SAFEARRAY *psa;

SAFEARRAYBOUND rgsabound[1];

_RecordsetPtr temp_rst;

temp_rst.CreateInstance(__uuidof(Recordset));

try{

temp_rst->Open((_variant_t)sqlstatement,_variant_t((IDispatch *)cnn,true),adOpenDynamic,adLockPessimistic,adCmdText);

}catch(_com_error &e){

CatchError(e);

return FALSE;

}

if(temp_rst->_EOF)

return FALSE;

if(pBuf)

{

rgsabound[0].lLbound = 0;

rgsabound[0].cElements = len;

psa = SafeArrayCreate(VT_UI1, 1, rgsabound);

for (long i = 0; i < (long)len; i++)

SafeArrayPutElement (psa, &i, pBuf++);

varBLOB.vt = VT_ARRAY | VT_UI1;

varBLOB.parray = psa;

temp_rst->GetFields()->GetItem((_variant_t)attrName)->AppendChunk(varBLOB);

}

temp_rst->Update();

temp_rst->Close();

return TRUE;

}

在实际的操作中,我们将常用的数据库操作整理为存储过程编译到数据库中,以下就是本系统所涉及的具体存储过程:

从厨师表中删除厨师(DeleteCook @cookid )

1)本过程先查看点菜表中是否存在相关记录,若存在,则不允许删除厨师,因为顾客还没结账;若不存在,则先删除做菜表中记录,再删除厨师表中记录。

--删除厨师,需先将CookingTable和DishedTable中的相关项删除

CREATE PROCEDURE DeleteCook @cookid char(8)

AS

--如果点菜表中含有相关项,说明顾客未结账,则不允许删除

IF EXISTS (SELECT * FROM DishedTable WHERE cookid=@cookid)

RETURN

ELSE

IF EXISTS (SELECT * FROM CookingTable WHERE cookid=@cookid)

DELETE FROM CookingTable WHERE cookid=@cookid

DELETE FROM CookTable WHERE cookid=@cookid

2)从菜品表中删除菜品(DeleteDish @dishid)

本过程同样先检查点菜表中是否有相关项,若有,则不允许删除菜品;若无,则先删除做菜表中记录,再删除菜品表中记录。

--删除菜品信息,先检查DishedTable和CookingTable中有无相关项

CREATE PROCEDURE DeleteDish @dishid char(8)

AS

--如果点菜表中含有相关项,说明顾客未结账,则不允许删除

IF EXISTS (SELECT * FROM DishedTable WHERE dishid=@dishid)

RETURN

ELSE

IF EXISTS (SELECT * FROM CookingTable WHERE dishid=@dishid)

DELETE FROM CookingTable WHERE dishid=@dishid

DELETE FROM DishesTable WHERE dishid=@dishid

3)销售统计(SalesStatistics @date,@sales)

本过程首先检查表中是否存在日期相同的记录,若存在,则将原记录中的销售额加上新数据;若不存在,则直接插入新数据。

--销售统计函数

CREATE PROCEDURE SalesStatistics @date char(10),@sales float

AS

--如果表中存在该项,则增加销售额

IF EXISTS (SELECT * FROM SalesStatisticsTable WHERE date=@date)

UPDATE SalesStatisticsTable SET sales=sales+@sales WHERE date=@date

ELSE

--否则,插入新数据

INSERT INTO SalesStatisticsTable (date,sales) VALUES(@date,@sales)

4)搜索拿手菜表(SearchSpecialty @cookname)

若cookname为'%%',则显示所有表中数据,否则,显示某一厨师的拿手菜信息。所返回结果先按厨师名排序,然后再按喜爱度排序。

--搜索拿手菜表

CREATE PROCEDURE SearchSpecialty @cookname nchar(50)

AS

IF @cookname='%%'

SELECT DT.dishid as 菜品编号,LEFT(dishname,LEN(dishname)) as 菜品名称,

CT.cookid as 厨师编号,LEFT(cookname,LEN(cookname)) as 厨师姓名,

average as 喜爱度,dishprice as 菜品单价

FROM SpecialtyTable ST INNER JOIN DishesTable DT ON ST.dishid=DT.dishid

INNER JOIN CookTable CT ON ST.cookid=CT.cookid

ORDER BY cookname ASC,average DESC  --先按厨师名排序,再按平均分排序

ELSE

SELECT DT.dishid as 菜品编号,LEFT(dishname,LEN(dishname)) as 菜品名称,

CT.cookid as 厨师编号,LEFT(cookname,LEN(cookname)) as 厨师姓名,

average as 喜爱度,dishprice as 菜品单价

FROM SpecialtyTable ST INNER JOIN DishesTable DT ON ST.dishid=DT.dishid

INNER JOIN CookTable CT ON ST.cookid=CT.cookid

WHERE cookname LIKE @cookname

ORDER BY cookname ASC,average DESC   --先按厨师名排序,再按平均分排序

5)点菜(DishedFuction @dishedtime ,@deskid @dishid ,@cookid)

本过程先查看表中是否存在相同记录,若存在,则将所点菜品份数amount加1,菜品总价cost自动加上相应菜品单价;若不存在,则直接插入新数据。

--点菜操作

CREATE PROCEDURE DishedFuction

@dishedtime char(19),@deskid int,@dishid char(8),@cookid char(8)

AS

DECLARE @price float

SELECT @price=dishprice FROM DishesTable WHERE dishid=@dishid

IF EXISTS (SELECT * FROM DishedTable WHERE dishedtime=@dishedtime AND deskid=@deskid AND dishid=@dishid)

UPDATE DishedTable SET amount=amount+1,cost=cost+@price

WHERE dishedtime=@dishedtime AND deskid=@deskid AND dishid=@dishid

ELSE

INSERT INTO DishedTable (dishedtime,deskid,dishid,cookid,cost,amount)

VALUES(@dishedtime,@deskid,@dishid,@cookid,@price,1)

6)退菜(ReturnDishFuction @dishedtime,@deskid,@dishid)

本过程先查看菜品份数amount是否为1,若为1,则直接删除该记录;若不为1,则将菜品份数amount减1,然后菜品总价cost减去相应菜品单价。

--退菜操作

CREATE PROCEDURE ReturnDishFuction

@dishedtime char(19),@deskid int,@dishid char(8)

AS    DECLARE @price float

SELECT @price=dishprice FROM DishesTable WHERE dishid=@dishid

--如果点菜表中存在该项则将点菜份数-1,菜品总价递减

IF EXISTS (SELECT * FROM DishedTable WHERE dishedtime=@dishedtime AND deskid=@deskid AND dishid=@dishid)

BEGIN  DECLARE @amount int

SELECT @amount=amount FROM DishedTable WHERE dishedtime=@dishedtime AND deskid=@deskid AND dishid=@dishid

IF @amount=1

DELETE FROM DishedTable WHERE dishedtime=@dishedtime AND deskid=@deskid AND dishid=@dishid

ELSE

UPDATE DishedTable SET amount=amount-1,cost=cost-@price

WHERE dishedtime=@dishedtime AND deskid=@deskid AND dishid=@dishid

END

7)评分(ScoreFuction @cookid,@dishid ,@score)

本过程先检查表中是否存在相同记录,若存在,则将评分次数freq加1,总分scores加上此次分数,并计算平均分;若不存在,则插入新数据。

--对厨师所做菜品进行评分

CREATE PROCEDURE ScoreFuction @cookid char(8),@dishid char(8),@score int

AS

--如果表中存在该项,则将评次加1,总分增加,并求出平均分

IF EXISTS (SELECT * FROM CookingTable WHERE cookid=@cookid AND dishid=@dishid)

BEGIN

DECLARE @f int,@s int,@a int

SELECT @f=freq,@s=scores FROM CookingTable WHERE cookid=@cookid AND dishid=@dishid

SET @f=@f+1

SET @s=@s+@score

SET @a=@s/@f

UPDATE CookingTable SET freq=@f,scores=@s,average=@a

WHERE cookid=@cookid AND dishid=@dishid

END

ELSE

INSERT INTO CookingTable (cookid,dishid,freq,scores,average)

VALUES(@cookid,@dishid,1,@score,@score)

8)搜索点菜表(SearchDished @dishedtime ,@deskid)

本过程用于向顾客返回其所点菜品信息,并对厨师所做菜品进行评分。

--搜索点菜表

CREATE PROCEDURE SearchDished @dishedtime char(19),@deskid int

AS

SELECT DdT.dishid as 菜品编号,LEFT(dishname,LEN(dishname)) as 菜品名称,

DdT.cookid as 厨师编号,LEFT(cookname,LEN(cookname)) as 厨师姓名,

amount as 点菜份数,cost as 菜品总价

FROM DishedTable DdT INNER JOIN DishesTable DsT ON DdT.dishid=DsT.dishid

INNER JOIN CookTable CkT ON DdT.cookid=CkT.cookid

WHERE dishedtime=@dishedtime AND deskid=@deskid

9)获取账单信息(GetAccountInfo @dishedtime,@deskid)

本过程用于结账时显示顾客所点菜品的详细信息。

--获取账单详细信息

CREATE PROCEDURE GetAccountInfo @dishedtime char(19),@deskid int

AS

SELECT DdT.dishid as 菜品编号,LEFT(dishname,LEN(dishname)) as 菜品名称,

DdT.cookid as 厨师编号,LEFT(cookname,LEN(cookname)) as 厨师姓名,

amount as 点菜份数,cost as 总价

FROM DishedTable DdT INNER JOIN DishesTable DsT ON DdT.dishid=DsT.dishid

INNER JOIN CookTable CkT ON DdT.cookid=CkT.cookid

WHERE dishedtime=@dishedtime AND deskid=@deskid

10)搜索菜品表(SearchDishes @dishname)

本过程显示搜索菜品表的结果。

--搜索菜品表

CREATE PROCEDURE SearchDishes @dishname nchar(50)

AS

IF @dishname='%%%%'

SELECT dishid as 菜品编号,LEFT(dishname,LEN(dishname)) as 菜品名称,dishprice as 菜品单价

FROM DishesTable

ELSE

SELECT dishid as 菜品编号,LEFT(dishname,LEN(dishname)) as 菜品名称,dishprice as 菜品单价

FROM DishesTable WHERE dishname LIKE @dishname

源代码下载地址:http://download.csdn.net/source/2406335 标题有误,请见谅...

酒店点餐系统开发详解(四)相关推荐

  1. 酒店点餐系统开发详解(三)

    酒店点餐系统开发详解(三) --通信模块设计 注:本系统通信实现采用CSocket类 在上一节的数据流图中可以看到顾客(点餐)终端和厨师(任务分配)终端之间有数据的流动,这看起来好像二者是直接进行的通 ...

  2. 酒店点餐系统开发详解(一)

    酒店点餐系统开发详解 --前言 信息管理系统老师让我们分组做一个信息管理系统,以让我们熟悉一下项目开发的过程,并以此锻炼自己的能力.说实话,刚开始做的时候也感觉很没底,因为我不知道这个项目最终能否成功 ...

  3. 酒店点餐系统开发详解(二)

    酒店点餐系统开发详解 --系统分析 一个好的系统,必须要进行完善而且全面的系统分析.系统分析做好了,那就能够指导项目良好地发展下去.当然,系统分析需要以需求分析为基础,不过,在本项目中并未做仔细的需求 ...

  4. 酒店点餐系统开发详解(五)

    酒店点餐系统开发详解(五) --任务分配设计 本系统从公平的角度,采取"先来先服务"原则为厨师分配做菜任务,但是顾客在点菜时可能出现指定了某个厨师做某道菜的情况,所以本系统针对未指 ...

  5. 酒店点餐系统开发详解(六)

    酒店点餐系统开发详解(六) --疑难解决 在本系统的详细设计过程中遇到了很多的麻烦,经过分析.思考和网上搜索等方式将所有问题均给一一化解了,现与大家分享以共勉. 1.CDataGrid的使用 之所以使 ...

  6. EasyPR中文开源车牌识别系统 开发详解

     在上篇文档中作者已经简单的介绍了EasyPR,现在在本文档中详细的介绍EasyPR的开发过程. 正如淘宝诞生于一个购买来的LAMP系统,EasyPR也有它诞生的原型,起源于CSDN的taotao ...

  7. EasyPR--中文车牌识别系统 开发详解(开源)

    人工智能AI与大数据技术实战  公众号: weic2c 一个开源的中文车牌识别系统, Git地址为:https://github.com/liuruoze/EasyPR. 我给它取的名字为EasyPR ...

  8. 酒店预约APP软件开发详解

    酒店预约APP软件开发主要是对于用户的需求来出示方便快捷服务项目,完成用户在手机端操纵方式,达到用户在操纵端.管理方法端.营销推广端这些平台的多样化更新扩展. 1.新闻资讯信息消息推送 根据剖析用户针 ...

  9. [编程思想]中控系统开发详解

    1.开发目的:多计算机.多投影机或者其他网络设备的开启关闭控制 2.开发目标:单台设备控制及状态显示:多台设备控制:分区域控制等等 3.开发硬件需求:基于本地局域网,电脑,投影机,交换机,网络继电器, ...

最新文章

  1. Fedora 16 正式版专题
  2. do_page_fault: epc == 00000000, ra == 00000000
  3. 程序员面试题精选100题(55)-不用+、-、×、÷做加法[算法]
  4. HTTP请求头中各字段解释
  5. Java黑皮书课后题第6章:**6.25(将毫秒转化成小时、分钟、秒数)使用下面的方法头,编写一个将毫秒数转换成小时数、分钟数和描述的方法,返回形式如“小时:分钟:秒“
  6. 鸿蒙os2.0游戏体验,华为运行鸿蒙OS 2.0体验:界面近似EMUI 11
  7. 在WordPress中添加简书风格的连载目录和文章导航
  8. [Unity3D]unity3d5.0简单的调用摄像头
  9. LeetCode 1816. 截断句子
  10. 如何用python的i2c教程_Micropython TPYBoard I2C的用法
  11. [今日白学]组件的基础的基础的基础
  12. 支持https协议么_你真的了解网址么?
  13. [DCDC](DC-DC) 电感计算有难题 ? 你我一起来学习
  14. SECS/GSM 测试工具
  15. 为什么要成为软件工程师
  16. 云计算与大数据——数据中心
  17. Prometheus的函数和计算公式
  18. java程序员创业需要_java程序员出路有哪些
  19. 题解 UVA12304 【2D Geometry 110 in 1!】
  20. 整理了一下以前写的东西,单条记载 现在看看还蛮有意思

热门文章

  1. Java下载海康历史视频并合并转码
  2. BUGKU easypicture
  3. UnsupportedEncodingException(转码异常)你可能忽略的地方都讲啦
  4. java产品分类和管理_Java生鲜电商平台-商品无限极目录的设计与架构
  5. excel去掉同一个单元格内重复的文字工具
  6. 【两周快速入门pr】五、生活化vlog——你第一个vlog小视频(附相机推荐)
  7. 区块链技术服务于税收治理的深圳实践
  8. 慎入坑:腾讯云轻量2核2G3M服务器30元不建议选择
  9. 分享一些不起眼的赚钱项目
  10. 主成分分析PCA的前世今生