⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch15.htm

📁 好书《C++ Builder高级编程技术》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
but the record that is currently in error will be left alone. That is, it 
will be
left at the invalid value assigned to it by the user.</P>
<P>If you set <TT>UpdateAction</TT> to <TT>uaRetry</TT>, that means you have attempted
to update the information in the current record and that you want to retry committing
it. The 
record you should update is the current record in the dataset passed as the
first parameter to <TT>OrdersTableUpdateError</TT>.</P>
<P>In the <TT>OrdersTableUpdateError</TT> method, I always choose <TT>uaSkip</TT>
as the value to assign to 
<TT>UpdateAction</TT>. Of course, you could pop up a dialog
and show the user the old value and the new value of the current record. The user
would then have a chance to retry committing the data. Once again, you retrieve the
data containing the 
current &quot;problem child&quot; record from the dataset passed
in the first parameter of <TT>OrdersTableUpdateError</TT>. I show an example of accessing
this data when I retrieve the old value of the <TT>OrderNo</TT> field for the record:</P>

<PRE><FONT COLOR="#0066FF">AnsiString Temp = DataSet-&gt;Fields[0]-&gt;OldValue;

Temp = + &quot;: &quot; + S;

ListBox1-&gt;Items-&gt;Add(Temp);

</FONT></PRE>
<P>Needless to say, the <TT>OldValue</TT> field is declared as a <TT>Variant</TT>
in the 
source code to <TT>DB.HPP</TT>, which is the place where the <TT>TDataSet</TT>
declaration is located:</P>
<PRE><FONT COLOR="#0066FF">System::Variant __fastcall GetOldValue(void);

...

__property System::Variant OldValue = {read=GetOldValue};


</FONT></PRE>
<P>Two other values are passed to the <TT>TableUpdateError</TT> method. The first
is an exception reporting on the current error, and the second is a variable of type
<TT>TUpdateKind</TT>:</P>
<PRE><FONT COLOR="#0066FF">enum TUpdateKind 
{ ukModify, ukInsert, ukDelete };

</FONT></PRE>
<P>The variable of type <TT>TUpdateKind</TT> just tells you how the current record
was changed. Was it updated, inserted, or deleted? The exception information is passed
to you primarily so that you can 
get at the message associated with the current error:</P>
<PRE><FONT COLOR="#0066FF">E-&gt;Message;

</FONT></PRE>
<P>If you handle the function by setting <TT>UpdateAction</TT> to a particular value,
say <TT>uaSkip</TT>, then BCB will not pop up a 
dialog reporting the error to the
user. Instead, it assumes that you are handling the error explicitly, and it leaves
it up to you to report the error or not, as you see fit. In this case, I just dump
the error into the program's list box, along with 
some other information.</P>
<P>That's all I'm going to say about cached updates. At this point, you should go
back and run the Cache program that ships with BCB. It covers all the same ground
covered in the preceding few pages, but it does so in a 
slightly different form.
In particular, it shows how to pop up a dialog so that you can handle each <TT>OnUpdateError</TT>
event in an intelligent and sensible manner.</P>
<P>In general, cached updates give you a great deal of power you can tap into 
when
updating the data in a dataset. If necessary, go back and play with the CachedUpdates
program until it starts to make sense to you. This subject isn't prohibitively difficult,
but it does take a few moments' thought to absorb the basic principles 
involved.
<H3><A NAME="Heading26"></A><FONT COLOR="#000077">Many-to-Many Relationships</FONT></H3>
<P>Many-to-many relationships are necessities in most relational database projects.
Suppose, for example, that you have a set of software routines that 
you want to store
in a database. Some of the routines you can use in DOS, some in UNIX, some in Windows
NT, and some in Windows 95. Some routines, however, apply to two or more of the operating
systems.</P>
<P>To track this information, you might try 
adding an OS field to your Routines table,
where OS stands for Operating System. This solution sounds simple enough. However,
there is one problem. The issue, of course, is that some routines will work with
more than one OS. For example, you may have 
a routine that works in Windows NT and
Windows 95, but not in UNIX or DOS. As a result, the fairly simple one-to-many relationship
you try to establish with the OS fields really needs to be converted into a many-to-many
relationship.</P>
<P>Here, for 
example, is a list of operating systems: 
<TABLE BORDER="1">
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="87" ALIGN="LEFT"><B>CODE</B></TD>
		<TD WIDTH="103" ALIGN="LEFT"><B>OS</B></TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="87" 
ALIGN="LEFT"><TT>1</TT></TD>
		<TD WIDTH="103" ALIGN="LEFT">DOS</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="87" ALIGN="LEFT"><TT>2</TT></TD>
		<TD WIDTH="103" ALIGN="LEFT">UNIX</TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="87" 
ALIGN="LEFT"><TT>3</TT></TD>
		<TD WIDTH="103" ALIGN="LEFT">Windows</TD>
	</TR>
</TABLE>
<BR>
<BR>
Here is a list of routines: 
<TABLE BORDER="1">
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="94" ALIGN="LEFT"><B>CODE</B></TD>
		<TD WIDTH="178" 
ALIGN="LEFT"><B><TT>FUNCTION_NAME</TT></B></TD>
		<TD ALIGN="LEFT"><B>OSCODE</B></TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="94" ALIGN="LEFT"><TT>1</TT></TD>
		<TD WIDTH="178" ALIGN="LEFT"><TT>FormatDriveC</TT></TD>
		<TD 
ALIGN="LEFT"><TT>1</TT></TD>
	</TR>
	<TR ALIGN="LEFT" rowspan="1">
		<TD WIDTH="94" ALIGN="LEFT"><TT>2</TT></TD>
		<TD WIDTH="178" ALIGN="LEFT"><TT>AssignAllIRQsToTheMouse</TT></TD>
		<TD ALIGN="LEFT"><TT>2</TT></TD>
	</TR>
</TABLE>
<BR>
<BR>
As you 
can see, the format shown here allows you to assign only one <TT>OSCODE</TT>
to each routine. The goal is to find a way to specify that a routine works in more
than one OS. As you will see, one good solution involves creating a third table that
stands 
in the middle, between the OS and FUNCTION tables shown here.</P>
<P>The rest of this section describes how to actually go about creating many-to-many
relationships. This subject is annoyingly complex, but one that you can master if
you take a little 
time to think things through. My basic goal is to break down this
process into a series of steps that you can follow whenever you have to create one
of these many-to-many relationships. I might be going too far to say that these steps
make the process 
simple. They do make it manageable, however.</P>
<P>In Listing 15.2, you will find the database definition for a simple set of InterBase
tables. You can run this definition through WISQL by choosing File | Run ISQL Script.
Alternatively, you can 
create a new database and pass through the key statements
shown here one at a time.</P>
<P>Beneath the data definition for the database, you will find the code to a program
called ManyToMany. This code, in Listings 15.3 through 15.5, shows how to 
handle
a many-to-many relationship in a BCB program.<BR>
<BR>
<A NAME="Heading27"></A><FONT COLOR="#000077"><B>Listing 15.2. The schema for a simple
database that can capture a many-to-many relationship.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">/* 
Extract Database c:\src\unleash2\data\man2man.gdb */

CREATE DATABASE &quot;c:\src\unleash2\data\man2man.gdb&quot; PAGE_SIZE 1024;

/* Table: ATTRIBS, Owner: SYSDBA */

CREATE TABLE ATTRIBS (ATTRIBNO INTEGER NOT NULL,

        ATTRIB VARCHAR(34),


PRIMARY KEY (ATTRIBNO));

/* Table: CUSTOMERS, Owner: SYSDBA */

CREATE TABLE CUSTOMERS (CUSTNO INTEGER NOT NULL,

        NAME VARCHAR(35),

PRIMARY KEY (CUSTNO));

/* Table: MIDDLE, Owner: SYSDBA */

CREATE TABLE MIDDLE (CUSTNO INTEGER,

        
ATTRIBNO INTEGER);

/* Grant permissions for this database */

</FONT></PRE>
<H3 ALIGN="CENTER"><FONT COLOR="#0066FF"></FONT></H3>
<P><A NAME="Heading28"></A><FONT COLOR="#000077"><B>Listing 15.3. The main form for
the ManyToMany 
program.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">#include &lt;vcl\vcl.h&gt;

#pragma hdrstop

#include &quot;Main.h&quot;

#include &quot;DMod1.h&quot;

#include &quot;Relater.h&quot;

#pragma resource &quot;*.dfm&quot;

TForm1 *Form1;

__fastcall 
TForm1::TForm1(TComponent* Owner)

: TForm(Owner)

{

}

void __fastcall TForm1::ChangeAttrBtnClick(TObject *Sender)

{

  RelateForm-&gt;RunDialogModal();

}

</FONT></PRE>
<H3 ALIGN="CENTER"><FONT COLOR="#0066FF"></FONT></H3>
<P><A 
NAME="Heading29"></A><FONT COLOR="#000077"><B>Listing 15.4. The Relater form
from the ManyToMany program.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">#include &lt;vcl\vcl.h&gt;

#pragma hdrstop

#include &quot;Relater.h&quot;

#include 
&quot;DMod1.h&quot;

#pragma resource &quot;*.dfm&quot;

TRelateForm *RelateForm;

__fastcall TRelateForm::TRelateForm(TComponent* Owner)

: TForm(Owner)

{

}

void __fastcall TRelateForm::RunDialogModal()

{

  FCustNo = 
DMod-&gt;CustomerTable-&gt;FieldByName(&quot;CustNo&quot;)-&gt;AsInteger;

  Caption = &quot;Attributes for &quot; + DMod-&gt;CustomerTable-&gt;FieldByName(&quot;Name&quot;)-&gt;AsString;

  ShowModal();

}

void __fastcall 
TRelateForm::bbInsertClick(TObject *Sender)

{

  InsertQuery-&gt;Params-&gt;Items[0]-&gt;AsInteger = FCustNo;

  InsertQuery-&gt;Params-&gt;Items[1]-&gt;AsInteger =

    DMod-&gt;AttributeTable-&gt;FieldByName(&quot;AttribNo&quot;)-&gt;AsInteger;

  
InsertQuery-&gt;ExecSQL();

  ViewAttribs();

}

void __fastcall TRelateForm::ViewAttribs()

{

  DMod-&gt;ViewAttributes(FCustNo);

}

void __fastcall TRelateForm::bbDeleteClick(TObject *Sender)

{

  DeleteQuery-&gt;Params-&gt;Items[0]-&gt;AsInteger 
= FCustNo;

  DeleteQuery-&gt;Params-&gt;Items[1]-&gt;AsInteger =

    DMod-&gt;ViewAttributesQuery-&gt;FieldByName(&quot;AttribNo&quot;)-&gt;AsInteger;

  DeleteQuery-&gt;ExecSQL();

  ViewAttribs();

}

void __fastcall TRelateForm::FormShow(TObject 
*Sender)

{

  ViewAttribs();

}



</FONT></PRE>
<P><A NAME="Heading30"></A><FONT COLOR="#000077"><B>Listing 15.5. The data module
for the ManyToMany program.</B></FONT></P>
<PRE><FONT COLOR="#0066FF">#include &lt;vcl\vcl.h&gt;

#pragma hdrstop


#include &quot;DMod1.h&quot;

#pragma resource &quot;*.dfm&quot;

TDMod *DMod;

__fastcall TDMod::TDMod(TComponent* Owner)

: TDataModule(Owner)

{

  ManyToMany

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -