📄 ado.html
字号:
<p>For navigating through the record set you can use the following member
functions of the Recordset object:</p>
<pre>HRESULT MoveFirst();</pre>
<pre>HRESULT MovePrevious();</pre>
<pre>HRESULT MoveNext();</pre>
<pre>HRESULT MoveLast();</pre>
<p>Their names speak for themselves and I won't explain their purposes anymore.
In addition to these functions, the BOFILE and EOFILE variables (remember that
we've renamed these variables when we imported the msado15.dll), provide
information where we are in the record set. BOFILE is true when we are
past the first record while EOFILE is true when we are past the last record.
A typical application would be:</p>
<pre>while (!pRset->EOFILE)
{
// Display the contents of the record set.
// . . .
pRset->MoveNext();
}</pre>
<h3>Accessing and Updating Field Data in the Recordset</h3>
<h4>Accessing Field Values</h4>
<p>Because ADO is intended to be used in other languages other than C++, there
is no straightforward way to access data from a record set, since the values are
of a variant type. And because these values are variant, we need to
convert them to their proper type to be able to make sense out of them.
For example:</p>
<pre>_variant_t vtItem;
CString strItem;
vtItem = pRs->GetCollect(_variant_t("item"));
vtItem.ChangeType(VT_BSTR);
strItem = vtItem.bstrVal;</pre>
<p>To make life easier I created a function that should bring some
uniformity to the way we access data:</p>
<pre>_variant_t FieldValue(const _RecordsetPtr pRS, const char *field)
{
return pRS->GetCollect(_variant_t(field));
}</pre>
<p>Applying this to the example above:</p>
<pre>CString strItem = (const char *)_bstr_t(FieldValue(pRset, "item"));
double basePrice = double(FieldValue(pRS, "baseprice")); // <-- Another example</pre>
<h4>Updating Field Values</h4>
<p>Updating field values entails the same tedious process. For example:</p>
<pre>_variant_t vtItem, vtValue;
vtItem.SetString("item");
vtValue.SetString("Power drill");
pRset->Update(vtItem, vtValue);</pre>
<p>Again, to make life easier, I created a function or, rather, a series of
overloaded functions in the spirit of the one I wrote to access data, to bring
uniformity in updating data. The third parameter should provide you a clue
on what each function does:</p>
<pre>void FieldValue(_RecordsetPtr pRS, const char *field, const short value)
{
pRS->Update(_variant_t(field), _variant_t(value, VT_I2));
}
void FieldValue(_RecordsetPtr pRS, const char *field, const long value)
{
pRS->Update(_variant_t(field), _variant_t(value, VT_I4));
}
void FieldValue(_RecordsetPtr pRS, const char *field, const float value)
{
pRS->Update(_variant_t(field), _variant_t(value));
}
void FieldValue(_RecordsetPtr pRS, const char *field, const double value)
{
pRS->Update(_variant_t(field), _variant_t(value, VT_R8));
}
void FieldValue(_RecordsetPtr pRS, const char *field, const char *value) // strings of type char*
{
pRS->Update(_variant_t(field), _variant_t(value));
}
void FieldValue(_RecordsetPtr pRS, const char *field, const wchar_t *value) // wide strings of type wchar_t*
{
pRS->Update(_variant_t(field), _variant_t(value));
}
void FieldValue(_RecordsetPtr pRS, const char *field, _bstr_t &value) // strings of type _bstr_t
{
pRS->Update(_variant_t(field), _variant_t(value));
}
void FieldValue(_RecordsetPtr pRS, const char *field, const unsigned char value)
{
pRS->Update(_variant_t(field), _variant_t(value));
}
void FieldValue(_RecordsetPtr pRS, const char *field, const bool value)
{
pRS->Update(_variant_t(field), _variant_t(value));
}
void FieldValue(_RecordsetPtr pRS, const char *field, const CY &value)
{
pRS->Update(_variant_t(field), _variant_t(value));
}
void FieldValue(_RecordsetPtr pRS, const char *field, const DECIMAL &value)
{
pRS->Update(_variant_t(field), _variant_t(value));
}</pre>
<p>Applying to our example above:</p>
<pre>FieldValue(pRset, "item", "Power drill");
FieldValue(pRset, "baseprice", 235.00); // <-- Another example</pre>
<h3>Adding and Deleting Records</h3>
<p>To add a new record to the record set call the Recordset object's AddNew()
function. Doing so adds a new, albeit, blank record to the record set
while making that record the current one. After the record is added you
can begin to update each field value using the PutCollect(). For example:</p>
<pre>pRset->AddNew();
pRset->PutCollect(_variant_t("item"), _variant_t("Lasgun"));
pRset->PutCollect(_variant_t("specification"), _variant_t("High-powered, medium range"));
pRset->PutCollect(_variant_t("baseprice"), _variant_t(3456.50));
pRset->PutCollect(_variant_t("actualprice"), _variant_t(3400.00));
pRset->PutCollect(_variant_t("supplier"), _variant_t(1));</pre>
<p>To delete a record, call the Delete() member function of the Recordset
object, which has the syntax:</p>
<pre>HRESULT Delete(enum AffectEnum AffectRecords);</pre>
<p>Where AffectEnum has the following values:</p>
<pre>enum AffectEnum
{
adAffectCurrent = 1,
adAffectGroup = 2,
adAffectAll = 3,
adAffectAllChapters = 4
};</pre>
<p>For example, to delete the current record:</p>
<pre>pRset->Delete(adAffectCurrent);
pRset->MovePrevious();
if (pRset->BOFILE)
pRset->MoveNext();</pre>
<h3>Finding a Specific Record</h3>
<p>To find the specific record in the record set, use the member function
Find(), which has the syntax:</p>
<pre>HRESULT Find(_bstr_t Criteria, long SkipRecords, enum <a href="#SearchDirectionEnum">SearchDirectionEnum</a> SearchDirection, const _variant_t &Start = vtMissing);</pre>
<p>Where SearchDirectionEnum has the values:</p>
<pre><a name="SearchDirectionEnum"></a>enum SearchDirectionEnum
{
adSearchForward,
adSearchBackward
};</pre>
<p>For example, to find the item that has the id of 23 after and including the
current record:</p>
<pre>pRet->Find("itemdid = 23", adSearchForward);</pre>
<h3>Error Handling</h3>
<p>Most of the member functions of the ADO objects return an HRESULT value that
will give us a clue of the how an operation fares. However, it would be
far elegant and better to use the C++ <i>try</i> and <i>catch</i> mechanism for
handling ADO errors. ADO objects throw an exception of type _com_error
whenever an error is encountered. The Description() member of _com_error
returns a meaningful description of the error encountered. For example:</p>
<pre>try
{
// Delicate ADO operations normally go here
// . . .
}
catch (_com_error &e) // Catch any error...
{
cerr << endl << (const char *)e.Description() << endl; // ...then show its description.
}</pre>
<h2><a name="Sample Code"></a>Sample Code</h2>
<p>This tutorial comes with supplementary sample programs that will further
demonstrate the concepts elaborated above.</p>
<ul>
<li><a href="sample/ADOTemplate.zip">ADOTemplate</a> - A console applet that
demonstrates opening a connection to the database, executing an SQL command
and navigating through a record set. [<a target = "_blank" href="images/ADOTemplate.jpg">screenshot</a>]<br>
</li>
<li><a href="sample/ADOMFC.zip">ADOMFC</a> - A program demonstrating how the concepts in the tutorial could
be applied in creating a simple but concrete database application in MFC.
[<a target = "_blank" href="images/ADOMFC.jpg">screenshot</a>]<br>
</li>
<li><a href="mysql.html">MySQL commands</a> - SQL statements used in creating the pcs database used in
the examples</li>
</ul>
<h2>Future Installments</h2>
<p>Watch out for Part II of this tutorial which would include a detailed
walkthrough of the creation of the MFC example program above and another program
with a different
approach to accessing and updating field values using ADO record binding.
'Till then, ciao and happy hacking!!!</p>
<p> </p>
<p>12302003<br>
Mark Jundo P. Documento<br>
<a href="mailto:javelinexxx@yahoo.com">javelinexxx@yahoo.com</a></p>
<p> </p>
<p class="cnotice">Copyright 2003-2004 Mark Jundo P. Documento</p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -