设为首页 收藏本站
查看: 551|回复: 0

[经验分享] visual c++ 2008进行MySQL编程(ODBC)-- (四) 终极实现 之 派生CRecordset 中

[复制链接]

尚未签到

发表于 2016-10-23 10:06:19 | 显示全部楼层 |阅读模式
  Visual C++ 2008进行MySQL编程这个系列已经出了好几篇了,如下:
  visual c++ 2008进行MySQL编程(ODBC) -- (一) 套装安装
  visual c++ 2008进行MySQL编程(ODBC) --(二) CDatabase操作数据库
  visual c++ 2008进行MySQL编程(ODBC) --三 查询数据库
  visual c++ 2008进行MySQL编程(ODBC)-- (四) 终极实现 之 派生CRecordset 上
  
  在上面的CDatabase操作数据库这块,使用的是CDatabase这个类执行一个我们要操作数据库的sql语句,比如:

        CString sql_str;
sql_str.Format(_T("delete from customer where cust_id = %d"), cust_id);
m_db_opr.ExecuteSQL(sql_str);
  现在不用了,我们使用CRecordset类的这几个函数来实现这一切:
  

AddNew  Prepares for adding a new record. Call Update to complete the addition.
Cancel  Update Cancels any pending updates due to an AddNew or Edit operation.
Delete  Deletes the current record from the recordset. You must explicitly scroll to another record after the deletion.
Edit    Prepares for changes to the current record. Call Update to complete the edit.
Update  Completes an AddNew or Edit operation by saving the new or edited data on the data source.

  

  具体这几个函数怎么用的,有空可以参考一下MSDN,这里我只补充一点,就是,AddNew和Edit操作调用之后,一定要调用Update才会更新到数据库,而Delete就不用了。
  
  接着上一讲,我们使用MFC ODBC机制从CRecordset派生了自己的类Ccostomer:

class Ccustomer : public CRecordset
{
public:
Ccustomer(CDatabase* pDatabase = NULL);
DECLARE_DYNAMIC(Ccustomer)
// Field/Param Data
  
  在customer.c里面有如此一段:

#error Security Issue: The connection string may contain a password
// The connection string below may contain plain text passwords and/or
// other sensitive information. Please remove the #error after reviewing
// the connection string for any security related issues. You may want to
// store the password in some other form or use a different user authentication.
CString Ccustomer::GetDefaultConnect()
{
return _T("DSN=chh1;DESCRIPTION={\x8fd9\x4e2a\x662fchh1 database table};SERVER=127.0.0.1;UID=zhoutianzuo;PWD=000000;DATABASE=chh1;PORT=3306");
}
  

  删除#error,修改为:

CString Ccustomer::GetDefaultConnect()
{
return _T("DSN=chh1;SERVER=127.0.0.1;UID=zhoutianzuo;PWD=000000;DATABASE=chh1;PORT=3306");
}
  
  然后在类Ccustomer里面添加两个变量,一个是id一个是name,这两个是和数据库对应的绑定值的设计了:

public:
int     db_cust_id;
CString db_cust_name;
  
然后,我们注册变量和数据库变量的关系,修改函数DoFieldExchange如下:

void Ccustomer::DoFieldExchange(CFieldExchange* pFX)
{
pFX->SetFieldType(CFieldExchange::outputColumn);
// Macros such as RFX_Text() and RFX_Int() are dependent on the
// type of the member variable, not the type of the field in the database.
// ODBC will try to automatically convert the column value to the requested type
RFX_Int(pFX, _T("[cust_id]"), db_cust_id);
RFX_Text(pFX, _T("[cust_name]"), db_cust_name);
}
  
实际上就是添加了两个绑定关系,这里一定要注意了,_T("[cust_id]"),中括号里面的cust_id,一定要和数据库里面的变量一致,中括号可以不要,有一个情况一定要的,就是数据库变量里面存在空格,比如定义为:cust id。
  还要注意个东西,就是我们可以看到构造函数里面,有这么定义:

Ccustomer::Ccustomer(CDatabase* pdb)
: CRecordset(pdb)
{
m_nFields = 0;
m_nDefaultType = dynaset;
}
  这个m_nFields是什么呢?这个就是我们绑定的量个数,所以我们要修改如下:

Ccustomer::Ccustomer(CDatabase* pdb)
: CRecordset(pdb)
{
m_nFields = 2;
m_nDefaultType = dynaset;
}
  因为我们注册了两个绑定量,所以要相应修改为2,如果不是2呢?那么程序运行的时候会抛出异常的。不信可以试试,当然很多人是忘记了,忘记了,就看看异样的异常长啥样,也不错的嘛。呵呵。
  我们在工程的类Cmy_dbDlg里面给对话框在第二篇文章里面做了add edit和del的操作,这里我们拿add的实现做一个修改,重写其实现,之前的实现是:

void Cmy_dbDlg::OnBnClickedAddNew()
{
// TODO: Add your control notification handler code here
int cust_id = 0 ;
CString cust_name;
if(!GetCustIdFromEdit(cust_id))
{
AfxMessageBox(_T("NULL cust id, return"));
return;
}
if(!m_cust_name.GetWindowTextLengthW())
{
AfxMessageBox(_T("NULL cust name, return"));
return;
}
m_cust_name.GetWindowTextW(cust_name);
try
{
CString sql_str;
sql_str.Format(_T("insert customer value (%d, '%s')"), cust_id, cust_name);
m_db_opr.ExecuteSQL(sql_str);
}
catch(CDBException* pe)
{
// The error code is in pe->m_nRetCode
pe->ReportError();
pe->Delete();
}
}
  我们不做sql语句的执行了,我们用派生的类来实现,不过在my_dbDlg.cpp的开始要添加头文件customer.h的支持:
  

#include "stdafx.h"
#include "my_db.h"
#include "my_dbDlg.h"
#include "customer.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

  在重写OnBnClickedAddNew的实现:

void Cmy_dbDlg::OnBnClickedAddNew()
{
// TODO: Add your control notification handler code here
int cust_id = 0 ;
CString cust_name;
if(!GetCustIdFromEdit(cust_id))
{
AfxMessageBox(_T("NULL cust id, return"));
return;
}
if(!m_cust_name.GetWindowTextLengthW())
{
AfxMessageBox(_T("NULL cust name, return"));
return;
}
m_cust_name.GetWindowTextW(cust_name);
Ccustomer my_record(&m_db_opr);
try
{
my_record.Open(CRecordset::snapshot, _T("customer"));
my_record.AddNew();
my_record.db_cust_id   = cust_id;
my_record.db_cust_name = cust_name;
if(!my_record.Update())
{
AfxMessageBox(_T("Add New failed!"));
}
}
catch(CDBException* pe)
{
// The error code is in pe->m_nRetCode
pe->ReportError();
pe->Delete();
}
}
  
  还是解释一下代码,不管是增删还是修改,首先必须打开数据库先,修改和删除需要先判断条目是否存在,而增加就不用了,如果不允许重复条目,而插入了重复条目,也会抛出异常的,但是没有关系,就权当是一个提醒,没有任何危害。而上面的Open函数,就相当的需要解释了,在绑定了数据库变量后,第二个参数仅仅需要给出一个数据库名字customer,相当于是 “"select cust_id, cust_name
from customer",至于这个Open该怎么输入,具体有MSDN为参考:

  The lpszSQL Parameter and the Resulting SQL String

  Case
  What you pass in lpszSQL
  The resulting SELECT statement




  1


  NULL


  SELECTrfx-field-listFROMtable-name
  CRecordset::Open callsGetDefaultSQL to get the table name. The resulting string is one of cases 2 through 5, depending on whatGetDefaultSQL returns.




  2


  A table name


  SELECTrfx-field-listFROMtable-name
  The field list is taken from the RFX statements inDoFieldExchange. Ifm_strFilter andm_strSort are not empty, adds theWHERE and/orORDER BY
clauses.





  3 *


  A complete SELECT statement but without aWHERE orORDER BY clause


  As passed. If m_strFilter andm_strSort are not empty, adds theWHERE and/orORDER BY clauses.




  4 *


  A complete SELECT statement with aWHERE and/orORDER BY clause


  As passed. m_strFilter and/orm_strSort must remain empty, or two filter and/or sort statements are produced.




  5 *


  A call to a stored procedure


  As passed.




  * m_nFields must be less than or equal to the number of columns specified in theSELECT statement. The data type of each column specified in theSELECT statement must
be the same as the data type of the corresponding RFX output column.

  
  具体的含义我就不翻译了,计算机这个玩意总要懂一点英语,有时候我翻译出来也总有词不达意的时候。
  那么我们看看运行结果如何吧,在添加之前,我们查看数据库:
   DSC0000.jpg
  添加一个条目,id为45,name为‘李四’:
   DSC0001.jpg
  添加后的结果如下:
   DSC0002.jpg
  
  很好,代码也简单多了,易于扩展,方便设计。
  剩下Edit Delete操作,我就不做了,大家自己做做哈,有问题联系我哈哈。
  下一文,就写一下遍历数据库,同时,涉及参数化等操作,那么这个系列就算了完美结束了。
  
  

  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-290137-1-1.html 上篇帖子: MySQL的10件事—它们也许和你预想的不一样 下篇帖子: <转>MySQL 事务没有提交导致 锁等待 Lock wait timeout exceeded
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表