BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

OPF: Designing ObjectState Framework
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design
View previous topic :: View next topic  
Author Message
Chau Chee Yang
Guest





PostPosted: Mon May 16, 2005 2:30 am    Post subject: OPF: Designing ObjectState Framework Reply with quote



Hi,

I am trying to design the Object State Framework, The State will be
used by RDBMS's for perform SQL updating. I try to enumerate some use
cases to attract more discussion about it:

class TObjectValue is a business domain class, we may treat it like
TInvoice or TCustomer. For example:

TObjectState = [osCreate, osInsert, osUpdate, osDelete, osClean]

TObjectValue = class
property
State: TObjectState;
end;

TInvoice = class(TObjectValue)
TCustomer = class(TObjectValue)

case 1:
When an Object is created:

o := TObjectValue.Create; // o.State := osCreate
o.New; // o.State := osInsert
o.Prop1 := Value1; // o.State := osInsert
o.Prop2 := Value2; // o.State := osInsert
PersistenceFactory.Save(o); // o.State := osClean

case 2:
o := TObjectValue.Create; // o.State := osCreate
PersistenceFactory.Save(o); // o.State := osCreate, Do nothing

case 3:
When an object is load from Persistence Layer:

o := TObjectValue.Create; // o.State := osCreate
PersistenceFactory.Load(o); // o.State := osClean
o.Edit; // o.State := osClean or osUpdate??
o.Prop1 := Value1; // o.State := osUpdate
o.Prop2 := Value2; // o.State := osUpdate
PersistenceFactory.Save(o); // o.State := osClean

case 4:
o := TObjectValue.Create; // o.State := osCreate
PersistenceFactory.Load(o); // o.State := osClean
PersistenceFactory.Save(o); // o.State := osClean, Do nothing

case 5:
When an object is deleted:

o := TObjectValue.Create; // o.State := osCreate
PersistenceFactory.Delete(o); // o.state := osCreate, Do nothing

case 6:
When an object is deleted:

o := TObjectValue.Create; // o.State := osCreate
PersistenceFactory.Load(o); // o.State := osClean
o.Delete; // o.State := osDelete
PersistenceFactory.Delete(o); // o.Clear, o.state := osCreate

I feel the way I design isn't good enough. I use methods like O.New,
O.Edit, O.Delete to set the ObjectState. This kind of coding is similar
to TDataSet's style. It seems like I were poisoned by TDataSet and hard
to get rid of it to design in true OO way. Would anyone share their
thoughts and ideas, please. Thank you.

--
Best regards,
Chau Chee Yang

E Stream Software Sdn Bhd
URL: www.sql.com.my
SQL Financial Accounting
Back to top
Stephane Fillon
Guest





PostPosted: Mon May 16, 2005 3:05 am    Post subject: Re: OPF: Designing ObjectState Framework Reply with quote



Quote:
TObjectState = [osCreate, osInsert, osUpdate, osDelete, osClean]

I would prefer not to give RDBMS state name.

TObjectState = [osNew, osDirty, osRemoved, osClean]
--

___________________________________________________________________
Stephane FILLON - mailto: [email]fillon72 (AT) yahoo (DOT) com.au[/email]

39 Balaton Street, Westlake QLD 4074 - Australia

Tel/Fax: +61 (07) 3279 7929
AACS: #3022270 - ICQ: #85420907 - Skype: graal72
GMT +10H


Back to top
Bob Dawson
Guest





PostPosted: Mon May 16, 2005 6:14 am    Post subject: Re: Designing ObjectState Framework Reply with quote



"Chau Chee Yang" wrote
Quote:

TObjectState = [osCreate, osInsert, osUpdate, osDelete, osClean]

I tend to agree with Stephane--name your states for the condition of the
object, not after DBMS actions.

Some considerations:
1. Is there really only one dimension here? Think about

Action on Save() call:
In Database
True False
Clean ignore ignore(?)
Dirty update insert
Deleted ignore ignore

2. I put the question mark on a clean insert--ignoring this may or may not
be right, depending on the convention and what 'clean' means. A new object
may have to be inserted in its default state if required by relational
integrity.

3. Consider the element of serialization within transactions.
Quote:
o.Prop2 := Value2; // o.State := osInsert
PersistenceFactory.Save(o); // o.State := osClean

That will be a problem for complex transactions. Consider
Object A created and Set (now dirty)
start transaction
PersistenceFactory.Save(A);
// what is the state of A? Isn't clean and isn't yet saved
// (transaction might be rolled back)
A.ChangeSomeProperty;
PersistenceFactory.Save(A);
// need to do an update here rather than another insert, because
// within the transaction frame the object already exists
PersistenceFactory.Commit();
//Object A now has known characteristics of being saved and clean.

Point--It's not enough for the object to have a single sense of its RDBMS
status, because that status doesn't change in a simple way. If an object is
submitted to the persistence layer more than once in the course of a
transaction, it has to know that and perhaps behave differently the second
time, evene though it cannot yet be told whether the original command
succeeded.

Note that this also affects deletes; after a call of
PersistenceFactory.Delete(o)
then any further command should be ignored even though the object cannot be
sure that the delete was carried out successfully until the transaction
completes.

bobD



Back to top
JFN
Guest





PostPosted: Mon May 16, 2005 8:21 am    Post subject: Re: Designing ObjectState Framework Reply with quote

Bob Dawson wrote:

Quote:
That will be a problem for complex transactions. Consider
Object A created and Set (now dirty)
start transaction
PersistenceFactory.Save(A);
// what is the state of A? Isn't clean and isn't yet saved
// (transaction might be rolled back)
A.ChangeSomeProperty;
PersistenceFactory.Save(A);
// need to do an update here rather than another insert, because
// within the transaction frame the object already exists
PersistenceFactory.Commit();
//Object A now has known characteristics of being saved and clean.


Interesting point.

Wouldn't some kind of a registration stack allow to reverse to any
previous state in case of a RollBack?

start transaction
PersistenceFactory.Save(A); => Push(A);
A.ChangeSomeProperty;
PersistenceFactory.Save(A); => Push(A);
PersistenceFactory.Commit(); => ReleaseStack()
except
PersistenceFactory.RollBack(); => Pop(A), ReleaseStack()

--
Jean-Francois Nifenecker, Bordeaux (EU)

Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Mon May 16, 2005 8:26 am    Post subject: Re: Designing ObjectState Framework Reply with quote

"Chau Chee Yang" <ccy (AT) sql (DOT) com.my> a écrit dans le message de news:
[email]428805c6 (AT) newsgroups (DOT) borland.com[/email]...

Quote:
I am trying to design the Object State Framework, The State will be
used by RDBMS's for perform SQL updating. I try to enumerate some use
cases to attract more discussion about it:

class TObjectValue is a business domain class, we may treat it like
TInvoice or TCustomer. For example:

TObjectState = [osCreate, osInsert, osUpdate, osDelete, osClean]

I would mainly agree with both Stephane and Bob. I honestly don't think you
need an Object State Framework though.

Now for the revolutionary (or should that be revolting?) stuff :-)

IMHO the only states you really need to take note of are whether an object
is dirty or not and whether an object has been deleted or not.

Assuming you have an ID inside your objects, then this is sufficient to
indicate whether an object is newly created and not yet persisted, as in
this state, the ID will be nil, null or 0.

So you would only really need a base class something like this :

TObjectValue = class
public
property ID: LongInt...
property IsDirty: Boolean... // readonly
property IsDeleted: Boolean... // readwrite
...
end;

Then you end up with code in the Persistence Layer like this :

function TPersistenceFactory.Store(obj: TObjectValue);
begin
if obj.IsDeleted then
raise Exception.Create('Can't store deleted object');

if not obj.IsDirty then // optional, see Bob's comment
Exit;

if ID <> 0 then
InternalUpdate(obj)
else
InternalInsert(obj);
end;

function TPersistenceFactory.Delete(obj: TObjectValue);
begin
if obj.IsDeleted then
raise Exception.Create('Object already deleted');

if obj.ID = 0 then
raise Exception.Create('Object has never been stored');

InternalDelete(obj);
end;

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker



Back to top
Chau Chee Yang
Guest





PostPosted: Mon May 16, 2005 9:05 am    Post subject: Re: Designing ObjectState Framework Reply with quote

Thank you the reply.

If I have someting like what Stephane suggest:

I := TInvoice.Create; (I.State is osNew)
PersistenceFactory.Load(I); (I.State is osClean)
I.Code.Value := '300-A01'; (I.State is osDirty)
I.DocAmt.Value := 300.00; (I.State is osDirty)

Am I right to say that if I perform the following opeations:

1. I.Revert or I.Undo

This operation should revert the delta back to each properties (Code and
DocAmt) and clear the delta. The I.State will set to osClean)


2. PersistenceFactory.Save(I)

This opeation should clear delta and set the I.State to osClean)


If it is what I said, I think I may need a Delta framework to keep track
the changes user have done. Code and DocAmt property must know it's
"Owner" (I, in this case) to set the Object's State when the property
value changed later.

--
Best regards,
Chau Chee Yang

E Stream Software Sdn Bhd
URL: www.sql.com.my
SQL Financial Accounting
Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Mon May 16, 2005 9:49 am    Post subject: Re: Designing ObjectState Framework Reply with quote

"Chau Chee Yang" <ccy (AT) sql (DOT) com.my> a écrit dans le message de news:
[email]4288623d (AT) newsgroups (DOT) borland.com[/email]...

Quote:
If I have someting like what Stephane suggest:

I := TInvoice.Create; (I.State is osNew)
PersistenceFactory.Load(I); (I.State is osClean)
I.Code.Value := '300-A01'; (I.State is osDirty)
I.DocAmt.Value := 300.00; (I.State is osDirty)

Am I right to say that if I perform the following opeations:

1. I.Revert or I.Undo

This operation should revert the delta back to each properties (Code and
DocAmt) and clear the delta. The I.State will set to osClean)

IMO, deltas should be handled with the Memento pattern; IOW, using an
external object to maintain a record of changing state.

So you would have two interfaces :

IMemento = interface
function IsEqualTo(const Other: IMemento): Boolean;
end;

IOriginator = interface
function CreateMemento: IMemento;
procedure SetMemento(const Memento: IMemento);
end;

and TObjectValue would implement IOriginator.

You can then also implement a History class that knows how to hold lists of
Mementos.


Quote:
2. PersistenceFactory.Save(I)

This opeation should clear delta and set the I.State to osClean)

Yes

Quote:
If it is what I said, I think I may need a Delta framework to keep track
the changes user have done. Code and DocAmt property must know it's
"Owner" (I, in this case) to set the Object's State when the property
value changed later.

Then you could use the Memento pattern and a History list to maintain the
Deltas, but you don't need to know the Owner of properties because you
change the Dirty flag in the setter methods of the properties.

procedure TCustomer.SetName(const value: string)
var
allowChange: Boolean;
args: TValueChangingArgs;
begin

if (fValue <> value) then
begin
allowChange := True;

if Assigned(fOnChanging) then
begin
args := TValueChangingArgs.Create(fName, value, allowChange);
try
fOnChanging(self, args);
finally
args.Free;
end;
end;

if allowChange then
begin
fName := value;
SetIsDirty(True);
if Assigned(fOnChanged);
fOnChanged(this.value);
end
else
raise ValueChangingException.Create(self, 'Name' fName, value);
end;
end;

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker



Back to top
Lee_Nover
Guest





PostPosted: Mon May 16, 2005 1:07 pm    Post subject: Re: Designing ObjectState Framework Reply with quote

On Mon, 16 May 2005 11:49:06 +0200, Joanna Carter (TeamB) <joanna (AT) nospam (DOT) .co.uk> wrote:
Quote:
if Assigned(fOnChanging) then
begin
args := TValueChangingArgs.Create(fName, value, allowChange);
try
fOnChanging(self, args);
finally
args.Free;
end;
end;


nice touch .. how would this be handled in an observer (using observer pattern) ?
a few observers could allow the change and other wouldn't ..
just a thought that crossed my mind :)

Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Mon May 16, 2005 1:34 pm    Post subject: Re: Designing ObjectState Framework Reply with quote

"Lee_Nover" <Lee_Nover[nospam]@delphi-si.com> a écrit dans le message de
news: op.sqvdewb0ignj8p (AT) stupidirko (DOT) ..

nice touch .. how would this be handled in an observer (using observer
pattern) ?
a few observers could allow the change and other wouldn't ..
just a thought that crossed my mind :)

This code was developed using C# because it allows multicast events; the
fOnChanging in C# would be such an event, but there is no reason why you
could not use the Observer pattern to broadcast notifications to multiple
Observers instead of calling a multicast event

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker


Back to top
Bob Dawson
Guest





PostPosted: Mon May 16, 2005 2:24 pm    Post subject: Re: Designing ObjectState Framework Reply with quote

"JFN" wrote
Quote:

Wouldn't some kind of a registration stack allow to reverse to any
previous state in case of a RollBack?

start transaction
PersistenceFactory.Save(A); => Push(A);
A.ChangeSomeProperty;
PersistenceFactory.Save(A); => Push(A);
PersistenceFactory.Commit(); => ReleaseStack()
except
PersistenceFactory.RollBack(); => Pop(A), ReleaseStack()

Not sure a stack would be appropriate, as generally only the initial state
of the object entering the transaction is going to be relative to a
rollback, no matter how many how many times the object is submitted to the
transaction.

If you mean a list of transaction members, then yes that's necessary if the
persistence layer is to notify all interested parties that the transcation
has completed/rolledback. Although here I use a FIFO list rather than a
stack: logically it seems to me that the first item involved in the
transaction should be the first notified of its success/failure, etc.

Member tracking at the transaction level for me solves the problem of
notification (in essence objects subscribe to the trransactions they
participate in), but doesn't solve the problem of remembering previous
object state. If BO marks itself as clean after the save() call, then was it
previously in a loaded or new condition? The object has to remember.

bobD



Back to top
Bob Dawson
Guest





PostPosted: Mon May 16, 2005 3:18 pm    Post subject: Re: Designing ObjectState Framework Reply with quote

"Joanna Carter (TeamB)" wrote
Quote:

Assuming you have an ID inside your objects, then this is sufficient to
indicate whether an object is newly created and not yet persisted, as in
this state, the ID will be nil, null or 0.

Not so fast there...

For collections and relationships objects may need to exchange credentials,
and in my approach that means that they need valid IDs from the moment of
creation. By assuming a nil ID for unsaved objects you're in effect
overloading the meaning of the ID--using nil as a magic flag for another
property (Saved/Unsaved).

Quote:
function TPersistenceFactory.Store(obj: TObjectValue);
begin
if obj.IsDeleted then
raise Exception.Create('Can't store deleted object');

This can be troublesome in the case of owned collections if the convention
is that owning objects save all owned items. If a collection member is
marked for deletion, then saving the owner twice can result in a deletion
the first time through, and an exception the second.

Additionally, for performance reasons it might be desirable to ignore the
call to save a dirty object if the object is both dirty and marked for
deletion.

Quote:
function TPersistenceFactory.Delete(obj: TObjectValue);
begin
if obj.IsDeleted then
raise Exception.Create('Object already deleted');

Why not just ignore?

Quote:
if obj.ID = 0 then
raise Exception.Create('Object has never been stored');

Again, why not just ignore?

bobD



Back to top
Bob Dawson
Guest





PostPosted: Mon May 16, 2005 3:22 pm    Post subject: Re: Designing ObjectState Framework Reply with quote

"Chau Chee Yang" wrote

Quote:
1. I.Revert or I.Undo

This operation should revert the delta back to each properties (Code and
DocAmt) and clear the delta. The I.State will set to osClean)

In general, I'd tend to regard .Revert as meaning restore to default
(unsaved obj) or 'as loaded' (saved obj) condition.

bobD



Back to top
Bob Dawson
Guest





PostPosted: Mon May 16, 2005 3:26 pm    Post subject: Re: Designing ObjectState Framework Reply with quote

"Joanna Carter (TeamB)" wrote

Quote:
if allowChange then
begin
fName := value;
SetIsDirty(True);
if Assigned(fOnChanged);
fOnChanged(this.value);
end
else
raise ValueChangingException.Create(self, 'Name' fName, value);
end;
end;

var
i : integer;
begin
x := TMyObj.CreateLoad(ID);
i := x.IntProp;
x.IntProp := i + 1;
x.IntProp := i;

Is x clean or dirty?

bobD





Back to top
JFN
Guest





PostPosted: Mon May 16, 2005 3:41 pm    Post subject: Re: Designing ObjectState Framework Reply with quote

Bob Dawson wrote:

Quote:
"JFN" wrote

Wouldn't some kind of a registration stack allow to reverse to any
previous state in case of a RollBack?

start transaction
PersistenceFactory.Save(A); => Push(A); [1]
A.ChangeSomeProperty;
PersistenceFactory.Save(A); => Push(A); [2]
PersistenceFactory.Commit(); => ReleaseStack()
except
PersistenceFactory.RollBack(); => Pop(A), ReleaseStack()

Not sure a stack would be appropriate, as generally only the initial
state of the object entering the transaction is going to be relative
to a rollback, no matter how many how many times the object is
submitted to the transaction.

A stack would allow to have several changes within the transaction, as
you pointed and to restore the BO to the current state when an
exception occurs.

In your exemple, the Pop(A) would alternatively restore to state in [1]
or state in [2] whether the corresponding instruction fails.

--
Jean-Francois Nifenecker, Bordeaux (EU)

Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Mon May 16, 2005 3:43 pm    Post subject: Re: Designing ObjectState Framework Reply with quote

"Bob Dawson" <bdawson (AT) idtdna (DOT) com> a écrit dans le message de news:
4288b9da$1 (AT) newsgroups (DOT) borland.com...

Quote:
Not so fast there...

For collections and relationships objects may need to exchange
credentials,
and in my approach that means that they need valid IDs from the moment of
creation. By assuming a nil ID for unsaved objects you're in effect
overloading the meaning of the ID--using nil as a magic flag for another
property (Saved/Unsaved).

I did mention "revolting" didn't I ? :-)

I would tend to take the approach of saving referred to and referring
objects in the same transaction, ensuring that the referred to object got
saved first.

I have a point of view that IDs are a necessary evil only really required
for persistence and have also considered the possibility of brokering
objects in such a way that the persistence broker is responsible for linking
the memory address of the object in a given process to the stored ID. In
that case, you would need a "virgin object" flag.

But then again, I always did like to stir in innovative ideas :-)

Quote:
function TPersistenceFactory.Store(obj: TObjectValue);
begin
if obj.IsDeleted then
raise Exception.Create('Can't store deleted object');

This can be troublesome in the case of owned collections if the convention
is that owning objects save all owned items. If a collection member is
marked for deletion, then saving the owner twice can result in a deletion
the first time through, and an exception the second.

Additionally, for performance reasons it might be desirable to ignore the
call to save a dirty object if the object is both dirty and marked for
deletion.

Plenty of options when discussing whether to raise exceptions or not.

Quote:
function TPersistenceFactory.Delete(obj: TObjectValue);
begin
if obj.IsDeleted then
raise Exception.Create('Object already deleted');

Why not just ignore?

if obj.ID = 0 then
raise Exception.Create('Object has never been stored');

Again, why not just ignore?

Also possible.

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker



Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design All times are GMT
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.