Board index » delphi » Filling Lists

Filling Lists


2007-01-20 05:42:28 AM
delphi42
Thanks to help from TeamB members I came up with this for filling a Listbox.
The names have been changed to generics, because I am uncomfortable posting
our actual code in a public forum.
Where Items is an ObjectList created in the DataModule OnCreate and freed in
the OnDestroy.
procedure TdmB.GetList(TheStrings: TStrings);
var Item : TItem;
begin
TheStrings.Clear;
With ibsql1 do
begin
With Transaction do
If Not InTransaction Then
StartTransaction;
Try
ParamByName('ID').AsInteger := dmA.ID;
ExecQuery;
While not Eof do
begin
Item := TItem.Create(FieldByName('irID').AsTrimString);
Items.Add(Item);
TheStrings.AddObject(FieldByName('NAME').AsTrimString, Item);
Next;
end;
Close;
Finally
With Transaction do
If InTransaction Then
Commit;
End;
end;
end;
Only then did it occur to me that I was tying my GUI to my DataModule, which
is what I have been working to avoid in single record code.
The first step is to maintain a separate list in the object layer. I could
even use the above, if it is alright for the data modules to see classes in
the object layer.
Are there any good examples anywhere showing connecting up datamodules to an
object layer with the populating of lists.
 
 

Re:Filling Lists

On Fri, 19 Jan 2007 15:42:28 -0600, Mark Reichert writes:
Quote
Where Items is an ObjectList created in the DataModule OnCreate and freed in
the OnDestroy.
You keep on adding items to this list but you never remove them or
reuse them?
Quote
If Not InTransaction Then
StartTransaction;
...
If InTransaction Then
Commit;
End;
The commit will always execute since you will always be in a
transaction at this point. You need to do something like:
TransactionNeeded := not InTransaction;
if TransactionNeeded then
StartTransaction;
...
if TransactionNeeded then
Commit;
Quote
Only then did it occur to me that I was tying my GUI to my DataModule, which
is what I have been working to avoid in single record code.
I don't really see how this ties the GUI to the Datamodule
implementation however you can always add an extra layer if you think
it will improve the separation.
Quote
The first step is to maintain a separate list in the object layer. I could
even use the above, if it is alright for the data modules to see classes in
the object layer.
Yes
--
Marc Rohloff [TeamB]
marc rohloff -at- myrealbox -dot- com
 

Re:Filling Lists

"Marc Rohloff [TeamB]" <"on request">writes
Quote
On Fri, 19 Jan 2007 15:42:28 -0600, Mark Reichert writes:

>Where Items is an ObjectList created in the DataModule OnCreate and freed
>in
>the OnDestroy.
You keep on adding items to this list but you never remove them or
reuse them?
Ah, sorry, I left out an ObjectList clear with the Strings clear. The
Objectlist is just intended to be a memory manager.
Quote
>If Not InTransaction Then
>StartTransaction;
...
>If InTransaction Then
>Commit;
>End;

The commit will always execute since you will always be in a
transaction at this point. You need to do something like:

TransactionNeeded := not InTransaction;
if TransactionNeeded then
StartTransaction;
...
if TransactionNeeded then
Commit;
I'm not sure how the two differ other than not having to call InTranaction
again.
Quote
>Only then did it occur to me that I was tying my GUI to my DataModule,
>which
>is what I have been working to avoid in single record code.
I don't really see how this ties the GUI to the Datamodule
implementation however you can always add an extra layer if you think
it will improve the separation.
Well, the GUI layer was making a direct call of a data module method. I
grant that is already a big improvement over letting the GUI have any access
to the database components, or worse, the data module knowing anything about
the GUI, but it still is a direct call.
Quote
>The first step is to maintain a separate list in the object layer. I
>could
>even use the above, if it is alright for the data modules to see classes
>in
>the object layer.
Yes
Thanks. I am just trying to do this project a lot better from an object
oriented design perspective, in the hopes of really easing maintenance.
 

Re:Filling Lists

"Mark Reichert" <XXXX@XXXXX.COM>writes
Quote
>>If Not InTransaction Then
>>StartTransaction;
>...
>>If InTransaction Then
>>Commit;
>>End;
>
>The commit will always execute since you will always be in a
>transaction at this point. You need to do something like:
>
>TransactionNeeded := not InTransaction;
>if TransactionNeeded then
>StartTransaction;
>...
>if TransactionNeeded then
>Commit;

I'm not sure how the two differ other than not having to call InTranaction
again.
I've figured it out. We only want to do the commit in this scope if the
transaction was started in this scope.
 

Re:Filling Lists

"Mark Reichert" wrote
Quote
I've figured it out. We only want to do the commit in this scope
if the transaction was started in this scope.
Right--that's the general idea..
However, this looks like you're just doing a single SELECT statement. If
that's true, you don't really need an explicit transaction at all.
bobD
 

Re:Filling Lists

"Bob Dawson" <XXXX@XXXXX.COM>writes
Quote
"Mark Reichert" wrote

>I've figured it out. We only want to do the commit in this scope
>if the transaction was started in this scope.

Right--that's the general idea..

However, this looks like you're just doing a single SELECT statement. If
that's true, you don't really need an explicit transaction at all.
I somehow had gotten the idea that it was good form to do so, particularly
when dealing with Interbase components.
 

Re:Filling Lists

"Mark Reichert" wrote
Quote

I somehow had gotten the idea that it was good form to do so,
particularly when dealing with Interbase components.
In general, the semantics of a transaction is that either all database
changes commit, or no changes commit (rollback). Since a select statement
doesn't (normally) change a database, there's nothing to commit.
If there's some specific reason to transaction wrap a select statement in
Interbase, that would be a definite peculiarity--but I will admit I am not an
Interbase user. You might want to ask about that on the sqlservers forum.
bobD
 

Re:Filling Lists

"Bob Dawson" <XXXX@XXXXX.COM>writes
Quote
"Mark Reichert" wrote
>
>I somehow had gotten the idea that it was good form to do so,
>particularly when dealing with Interbase components.

In general, the semantics of a transaction is that either all database
changes commit, or no changes commit (rollback). Since a select statement
doesn't (normally) change a database, there's nothing to commit.

If there's some specific reason to transaction wrap a select statement in
Interbase, that would be a definite peculiarity--but I will admit I am not an
Interbase user. You might want to ask about that on the sqlservers forum.
********
One thing you have to get used to when you start working with InterBase is
that everything happens within a transaction. Even a simple SELECT to fetch
some rows must take place within a transaction. If you do not explicitly
start and commit or rollback a transaction InterBase Express will
automatically wrap each SELECT and each row insert, update or delete in its
own transaction. While this may be acceptable in many situations,
particularly SELECT queryies, you will want to explicitly start and end
transactions in any case where the transaction must include more than one
change to one row in one table.
********
So, my doing it for a single SELECT is unnecessary, but would be advisable
for all other cases.
But I didn't come to oodesign to talk about Interbase. it is merely the
database from which I am fetching information to put in my list. I still
haven't seen a good example of how to both have loose coupling and have the
database stuff a container with objects of the appropriate type based
information in the database.
 

Re:Filling Lists

"Mark Reichert" wrote
Quote
I still
haven't seen a good example of how to both have loose
coupling and have the database stuff a container with objects
of the appropriate type based information in the database.
Fair enough.
In my system I have got a TLookupList item that functions as a sort of
dictionary class. The persistence layer manager maintains these as a list of
lists.
Lookups are structured as ID, Name, and Description. They have no save
method.
PL management is mostly a matter of persistence latency: Lookups are lazy
loaded, and maintained in memory for X minutes after the last access. Since
all calls route through a lookup manager, it can track that (it maintains
LastTouch(dateTime) on each lookup list) and clean itself up as necessary.
PL access calls include
FrameServices.ListFillStrings(const LookupName : string; aStrList :
TStrings);
FrameServices.ListIdOfItem(const LookupName : string; const Item : string) :
TBObjectId;
FrameServices.ListItemOfID(const LookupName : string; const aId :
TBObjectId) : string;
FrameServices.ListDescriptionOfItem(const LookupName : string; const Item :
string) : string;
FrameServices.ListDescriptionOfID(const LookupName : string; const aId :
TBObjectId) : string;
The GUI can fill a listbox etc using the ListFillStrings method.
Getting something like CustID from CustName or ProductName from ProductID is
handled by the next two calls.
This allows selection boxes etc on the GUI, reading the form's current
selection, etc., without direct db knowledge.
Unlike a normal BO class, a lookup list item cannot depend directly on SQL
autogen, since a lookuplist item might come from anywhere. How you negotiate
that issue depends entirely on the OPF framework design and capabilities.
bobD