21.4.7 创建订单ID(1)
要创建新订单的ID,需要Orders表的记录集。在Class View中右击DBSimpleUpdate,并从弹出菜单中选择Add | Class菜单项。选择MFC ODBC Consumer模板,并单击Add按钮;然后选择Northwind数据库,并选择Orders表作为该记录集的数据源。选择Dynaset作为记录集的类型,因为在需要添加新订单时要重用该记录集。输入类名COrderSet以及相应的文件名OrderSet.h和OrderSet.cpp。单击Finish按钮创建这个类。可以将新类的CStringW成员修改成CString类型,并使OrderSet.cpp类中的#error指令以注释形式存在。
1. 存储新订单的ID
现在将对记录集进行更深入的操作。开始在CCustomerView类中创建新订单时,需要创建一个独特的订单ID,因此需要考虑最适合做这件事的位置以及做这件事的过程。虽然新ID显示在CCustomerView对象表示的视图中的某个编辑控件内,但创建新ID实际上应该是COrderSet对象的责任,因为新ID实质上依赖于该记录集中的数据。一种好的方法是在CCustomerView类中添加一个可以使用属于COrderSet对象的函数进行设置的、用来设置编辑控件中ID值的变量。
回到Design窗口中的IDD_CUSTOMER_FORM对话框窗体上,右击对应订单ID的编辑控件-- 该控件的ID是IDC_NEWORDERID。从弹出菜单中选择Add Variable,然后输入变量名。像图21-18所显示的那样选择变量的类型和类别。
|
| (点击查看大图)图 21-18 |
变量类型默认是CString,因此务必将其设置为long。用来与编辑控件交换数据的DDX_Text()函数有许多重载版本,以适应该对话框下拉列表中显示的不同数据类型。
2. 创建新订单的ID
COrderSet对象属于文档对象,因此除Application Wizard创建的m_DBSimpleUpdateSet成员以外,再给CDBSimpleUpdateDoc类添加一个名为m_OrderSet的public数据成员。添加该成员的方法照例是在Class View中右击类名,并从弹出菜单中选择Add | Add Variable。COrderSet对象是在创建文档对象时自动创建的。有了对应文档中订单集的对象,任何需要该记录集的视图类就都可以访问它。
可以给COrderSet类添加一个新的成员函数,以生成独特的新订单ID。转到Class View中添加函数CreateNewOrderID(),其返回类型是long,没有形参。
CreateNewOrderID()函数需要做的第一件事情是检查记录集是否已经打开:
- long COrderSet::CreateNewOrderID()
- {
- if(!IsOpen())
- Open(CRecordset::dynaset);
-
- // Rest of the function implementation...
- }
如果记录集已经打开,在if语句中调用的IsOpen()函数就返回TRUE,否则返回FALSE。为了打开记录集,要调用从CRecordset继承的Open()成员。该函数以第一个实参指定的记录集类型对数据库执行一次SQL查询。第一个实参指定的类型是CRecordset::dynaset,即以动态集形式打开记录集-- 这是我们所期待的。巧合的是,该实参是不必要的,因为如果将其省略,则创建COrderSet类时将应用指定的默认值-- dynaset。不过,这里没有省略该实参,暗示着下面将叙述该实参的其他选项,见表21-5。
表 21-5
|
CRecordset::snapshot< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> |
记录集作为快照打开,
上一章讨论过快照和动态集 |
|
CRecordset::forwardonly |
打开的记录集是只读的,
而且只能向前滚动(当记录集
被打开时,自动定位在第一条记录上) |
|
CRecordset::dynamic |
打开的记录集可以在两个方
向上滚动,其他用户作出的修
改可以反映在记录集字段中 |
|
AFX_DB_USE_DEFAULT_TYPE |
使用继承成员m_nDefaultType存
储的默认记录集类型打开记录集,该
成员是在构造函数中初始化的 |
Open()函数还有两个形参,这里使用的是默认实参值。第二个形参是一个字符串指针,被指向的字符串可能是表名、SQL SELECT语句、预定义查询过程的调用,或者是空值(默认值)。如果是空值,则使用GetDefaultSQL()函数返回的字符串。第三个形参有点儿神秘,可用来指定无数的连接选项。比如使打开的记录集成为只读的,这意味着完全不能向记录集写出新记录;或者只允许追加记录,这样将禁止编辑或删除现有记录。在Open()函数的文档中,可以找到与该形参有关的更多细节。
在打开记录集之后,希望扫描所有记录,以找出OrderID字段中的最大值。可以添加下面的代码来实现这一点:
- long COrderSet::CreateNewOrderID()
- {
- if(!IsOpen())
- Open(CRecordset::dynaset);
- // Check for no records in recordset
- long newOrderID = 0;
- if(!(IsBOF() && IsEOF()))
- { // We have records
- MoveFirst(); // so go to the first
- while(!IsEOF()) // Compare with all the others
- {
- // Save order ID if its larger
- if(newOrderID < m_OrderID)
- newOrderID = m_OrderID;
-
- MoveNext(); // Go to next record
- }
- }
- return ++newOrderID;
- }
如果超出记录集中的第一条或最后一条记录,则记录集类的IsBOF()和IsEOF()成员将分别返回true;这种情况表明当前没有任何活动的记录,因此不应该使用记录集的字段。当记录集为空时,这两个函数都返回TRUE。只要记录集中有记录,就调用MoveFirst()成员函数移动到第一条记录上。还有一个转到记录集中的最后一条记录的MoveLast()成员。
创建初值为0的局部变量newOrderID,该变量最终要存储表中最大的订单ID。while循环使用MoveNext()成员函数,遍历记录集中的每一条记录,寻找更大的m_OrderID成员值。在调用记录集的任何移动成员之前,必须根据前进的方向,相应调用IsEOF()或IsBOF()函数。如果在超出记录集的结束或开始时还调用某个移动函数,则该函数将抛出一个CDBException类型的异常。