-
Saving Object Hierarchies
Let's assume I have an object called CTransaction. I give it a LoadData
method so it can fetch itself from the database and populate its own properties.
I should really represent a Transaction with 2 objects,
one which has all the Properties and Methods of a Transaction
and another which just worries about loading and saving Transactions. I'll
call the second one CTransactionDB.
Nothing too original there.
I should now be able to create a CTransaction object set it's
properties and call 'Save'. CTransaction would create an instance of CTransactionDB
and would pass all of it's properties to CTransactionDB in one go. It could
then call the 'Save' method of CTransactionDB which would take care of the
saving.
From what I can gather most people seem to think that the interface of DB
objects is pretty standard, you provide some way to Load, Save and Delete
and not much else. You certainly don't
mimick the properties of the Business object.
But here's a problem. Let's assume that you now want to create
a CBatch object which will contain a collection of CTransactions.
I can add Transactions to the Batch in the Client app without
ever hitting the database. Eventually I will want to
save the Batch, and all it's associated transactions.
Let's complicate things be saying that when the Batch is
saved its ID is generated by an AutoIncrement field. So
to get the ID of the batch we have to hit the database.
But let's also assume that each Transaction has a Batch
property.
We can't set the Batch property for the Transactions until
we have hit the database to save the Batch and thus generate
it's ID.
So our Options seem to be:
1. Save the Batch first, without saving any Transactions.
Have the Batch ID passed back from the Batch Save
so that you can then set the Batch properties of the
transactions in the Business layer. When they have been
updated you can then save them.
Problem: This involves an extra trip to the database.
Ideally we'd like the entire Batch and Transactions to
get saved in one trip. Apart from the performance issue,
it just feels like it should happen in one place.
2. The Second option is to send the Batch and All the
transactions to be saved at the same time. When the
Batch get's saved it could iterate through it's
Transactions and set their Batch property.
Problem: I said earlier that DB objects shouldn't have
properties. Is this a special case? I hate special
cases.
I'd appreciate any thoughts. This problem can get very messy
if you allow hierarcies of arbitrary depth. Is there any
consensus on saving object hierarchies? The books seem
to take very simple examples, as usual.
-Richard
-
Re: Saving Object Hierarchies
Well, there are some alternatives. You can use temporary IDs until an object
is saved.
I often use negative sequence numbers for such purpose. The database objects
are strictly positive, initialized objects are strictly negative, a
constructed, empty object may have an ID of 0 if there is a need to
distinguish between a contructed and initialized obect. The need for a
distinction may be driven by UI requirements. If you hit new, make changes,
then close, it is fairly obvious you'll want to ask the user whether to save
the changes. But hitting new, then cancel may not warrant a message box.
Hth
<Pierre />
-
Re: Saving Object Hierarchies
"Pierre G. Boutquin" <boutquin@home.com> wrote:
>Well, there are some alternatives. You can use temporary IDs >until an object
is saved.
I'm not sure I understand this.
If I am saving a Header object and a number of it's child
objects, I need to set some property of the child object
at the point where the Header object is saved, so that the child
objects will have the appropriate link to the header object.
But I don't know the ID of the Header object until I save it,
so I end up setting properties of the child objects in
the Database layer.
You seem to be suggesting that in the client application
I give the Header object a negative ID (say -1). And I then
assign -1 to the appropriate property of the child objects.
I can do this in the business layer no problem. But I still
have the problem that when I save the batch, and it gets
it's real ID, I need to somehow pass that ID to each child object
so that when they save themselves to the DB they have the appropriate link.
The approach I've taken incidently is to create a method
in DB objects called 'SetSaveTimeProperties' which
can accept any properties which might need to be set
during a save. I'm not entirely happy with this
but it beats having to create Property Lets for every
property.
-Richard
-
Re: Saving Object Hierarchies
Richard,
Fundemental questions: Why is it wrong to have the Data Centric layer
objects talk to each other? In this case why can't a CBatchDB object
inform a bunch of CTransactionDB objects of it's ID?
In this case a single network round trip is expected to save the batch and
its transactions. So there must be some controlling object that acts as
the entry point for this action possibly the CBatchDB object itself. I
don't see any reason why these two classes shouldn't cooperate to get this
done.
Another solution (one that I use) is to not use Database generated IDs. In
this case when a CBatch is created I assign it a unique ID on the spot. Of
course this means overcoming the non-trival problem of ensuring all IDs are
unque regardless of where they are generated .
--
Anthony Jones
Nuesoft Ltd
-
Re: Saving Object Hierarchies
From an OOP point of view, you don't need the IDs.
A Batch will know every Transactions contained, and if it's necessary each
Transaction will know the Batch they belong.
The ID is needed only in the database to distinguish Batches, and to relate
a Transaction to a Batch. If updating/deleting Batches or Transaction is
needed, then at least they need to know their database ID. But that
information could be private.
So:
- Why not let CBatch save everything by CBatch.SaveDb.
- SaveDb calls CBatchDb.Save and passes the Batch and Transactions data.
CBatchDb.Save returns the Batch database ID.
- CBatch keep track of its database ID.
- If a Transaction need to know the Batch ID, it askes for it from the
Batch.
A single Transaction may need to know its database ID, but the ones
contained in a Batch need not. The Batch can create an ID unique for each
Transaction within the Batch. When you need to update/delete a Transaction,
let the Batch do it.
For the single case Transaction, use a Batch with one Transaction.
Is this useable?
Best regards,
Thomas
<Richard Dalton .> wrote in message news:3a3adc14$1@news.devx.com...
>
> 2. The Second option is to send the Batch and All the
> transactions to be saved at the same time. When the
> Batch get's saved it could iterate through it's
> Transactions and set their Batch property.
>
-
Re: Saving Object Hierarchies
"Thomas Eyde" <thomas.eyde@bdc.no> wrote:
>- Why not let CBatch save everything by CBatch.SaveDb.
>- SaveDb calls CBatchDb.Save and passes the Batch and
> Transactions data.
>- CBatchDb.Save returns the Batch database ID.
>- CBatch keep track of its database ID.
>- If a Transaction need to know the Batch ID, it askes for it
> from the Batch.
It's certainly novel. I had assumed that adding a Batch property to the
Transaction was the obvious way to go.
You're right of course that the Transactions only need to store their Batch
in the DB, they don't need to have a batch property necessarily. As long
as there is a Batch to take care of the loading and saving.
One problem is that for a Transaction to find out it's ID
it needs to ask it's parent, so you are getting into circular
reference territory.
I assume lots of people have hit this problem. Although
I've talked to a few people who seem to be using Objects as
if they were old style API DLLs. i.e. collections of Functions.
It seems pretty common to have objects that have lots of similar
functions that work almost like stored precedures. There's
no concept of properties or Object Hierarchies.
Is that fair to say, or will someone out there tell me that
Object Oriented programming is alive and well in the n-Tier
world.
-Richard
><Richard Dalton .> wrote in message news:3a3adc14$1@news.devx.com...
>>
>> 2. The Second option is to send the Batch and All the
>> transactions to be saved at the same time. When the
>> Batch get's saved it could iterate through it's
>> Transactions and set their Batch property.
>>
-
Re: Saving Object Hierarchies
I also have used the method of generating a unique ID in the application
instead of at the database. In the MS world, we have the OS generate a GUID
for us. Always unique, and we have never had a problem with it.
--
Brian G. Rice
Entier Solutions Inc.
"Anthony Jones" <yadayadayada@msn.com> wrote in message
news:3a3d1635@news.devx.com...
> Richard,
>
> Fundemental questions: Why is it wrong to have the Data Centric layer
> objects talk to each other? In this case why can't a CBatchDB object
> inform a bunch of CTransactionDB objects of it's ID?
>
> In this case a single network round trip is expected to save the batch and
> its transactions. So there must be some controlling object that acts as
> the entry point for this action possibly the CBatchDB object itself. I
> don't see any reason why these two classes shouldn't cooperate to get this
> done.
>
> Another solution (one that I use) is to not use Database generated IDs.
In
> this case when a CBatch is created I assign it a unique ID on the spot.
Of
> course this means overcoming the non-trival problem of ensuring all IDs
are
> unque regardless of where they are generated .
>
> --
> Anthony Jones
> Nuesoft Ltd
>
>
>
-
Re: Saving Object Hierarchies
"Anthony Jones" <yadayadayada@msn.com> wrote:
>Fundemental questions: Why is it wrong to have the Data Centric >layer objects
talk to each other? In this case why can't a >CBatchDB object inform a bunch
of CTransactionDB objects of >it's ID?
I have no problem with that, In fact what I do is make the
Batch Object call a method on the Transaction object
to set any properties that can only be set in the DB layer.
In this case only one, but there could be more in some cases.
I absolutely think objects in the DB Layer should talk to
each other. My problem is the question of properties.
We don't know how future objects might like to communicate
with the Transaction object in the DB layer. If our method
of communication is through properties, then we might as well
expose the same properties in the DB layer as the Business layer,
since some future DB object might like to talk to the
Transactions Amount property for instance.
I seems like this would be a really bad route. The example
I gave was a typical example, but it's the wider issue of
what DB objects should expose that interests me.
Having too much code to manage the relationships between objects
in the DB layer also seems to be stealing or at least mimicking some of the
so called business rules that should supposedly be one layer up.
Perhaps I'm being too picky.
I think I'll stick with having a method in the DB objects
that lets me set any values that need to be set. I'll
continue to avoid exposing business type properties in the
DB Layer.
-
Re: Saving Object Hierarchies
Brian,
Do you then use those GUIDs as foreign keys in referencing tables?
If so, does it not bloat the record size excessively compared to an int?
I considered using GUIDs but I have several tables which carry little real
data, just a set of foreign keys.
--
Anthony Jones
Nuesoft Ltd
-
Re: Saving Object Hierarchies
>>
One problem is that for a Transaction to find out it's ID
it needs to ask it's parent, so you are getting into circular
reference territory.
<<
Circular references are fine.
It's better to simply accept circular references and put in place stratergy
to manage them. The alternative is to fight tooth and nail trying to
avoid them in all sorts of unique situations.
--
Anthony Jones
Nuesoft Ltd
-
Re: Saving Object Hierarchies
It does bloat it a little bit, but not enough to matter (IMHO). I am
dealing with enterprises where our Databases are often >20 Gigs, if not
more. A couple of extra bytes for a GUID Key is not relevant. I felt that
the guarantee of uniqueness was worth it.
Cheers,
--
Brian G. Rice
Entier Solutions Inc.
"Professional Architecture + Formalized Process = Repeatable Success"
www.entier.org
"Anthony Jones" <yadayadayada@msn.com> wrote in message
news:3a3fdaed@news.devx.com...
> Brian,
>
> Do you then use those GUIDs as foreign keys in referencing tables?
> If so, does it not bloat the record size excessively compared to an int?
>
> I considered using GUIDs but I have several tables which carry little real
> data, just a set of foreign keys.
>
> --
> Anthony Jones
> Nuesoft Ltd
>
>
>
-
Re: Saving Object Hierarchies
"Brian G. Rice" <bgrice@entier.org> wrote in message
news:3a409228$1@news.devx.com...
> A couple of extra bytes for a GUID Key is not relevant.
The benefit is that you can avoid a network trip. You can e.g. offload the
GUID generation to the client. A sequence requires a network trip and can
cause hotspots.
<Pierre />
-
Re: Saving Object Hierarchies
"Anthony Jones" <yadayadayada@msn.com> wrote:
>I considered using GUIDs but I have several tables which carry >little real
data, just a set of foreign keys.
I'm the same. Using GUIDs feels strange, but what the guy's
are saying does make some sense. I don't know it would
work in all cases. For one thing it's nice to go in and
create a query now and then, and know that you are looking
for all transactions with a batch id of 13.
I know you could copy and paste the GUID, but I still think
it'd me messy. Maybe I'm wrong.
I suppose there are other ways of generating a key.
You could use the date and time, in the following format.
yyyymmddhhnnss or yyyymmdd.hhnnss
I use the latter at the moment for Time stamping. I hadn't
considered using it as a Key. Of course there's the problem
of creating multiple objects at the same time. Particularly
accross machines.
Actually forget it, if you are generating the key on the client,
the GUID is the only way.
-Richard
-
Re: Saving Object Hierarchies
"Anthony Jones" <yadayadayada@msn.com> wrote:
>Brian,
>
>Do you then use those GUIDs as foreign keys in referencing tables?
>If so, does it not bloat the record size excessively compared to an int?
>
>I considered using GUIDs but I have several tables which carry little real
>data, just a set of foreign keys.
>
We use a Number(15) for our primary keys and foreign keys. Number(9) which
won't overflow a long could become exhausted in a very long-duration system
with a lot of transactions.
In VB our Number(15) is handled in a Variant (Decimal) datatype -- our Java
code uses variously BigDecimal (handled via JDBC) and occasionally BigInteger
(unfortunately not handled via JDBC).
We use an Oracle sequence to generate all these keys.
Matthew Cromer
-
Re: Saving Object Hierarchies
"Richard Dalton" . wrote:
>
>
>"Anthony Jones" <yadayadayada@msn.com> wrote:
>>I considered using GUIDs but I have several tables which carry >little
real
>data, just a set of foreign keys.
>
>
>I'm the same. Using GUIDs feels strange, but what the guy's
>are saying does make some sense. I don't know it would
>work in all cases. For one thing it's nice to go in and
>create a query now and then, and know that you are looking
>for all transactions with a batch id of 13.
>I know you could copy and paste the GUID, but I still think
>it'd me messy. Maybe I'm wrong.
>
>I suppose there are other ways of generating a key.
>You could use the date and time, in the following format.
>
>yyyymmddhhnnss or yyyymmdd.hhnnss
>
>I use the latter at the moment for Time stamping. I hadn't
>considered using it as a Key. Of course there's the problem
>of creating multiple objects at the same time. Particularly
>accross machines.
>
>Actually forget it, if you are generating the key on the client,
>the GUID is the only way.
We use a Sequence, but the client doesn't have to put it when writing a row.
All of our tables have a trigger to fill in the ID if it is blank on an
insert.
Both ways seem good to me, I just prefer the aesthetics of an incrementing
sequence over a GUID.
The real win for us is we are 100% consistent with our databases. All relationships
are via this synthetic key (ID), every table has ID as its primary key.
It lets us write some relatively simple and straightforward generic code
to create rich clients.
Matthew Cromer
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Development Centers
-- Android Development Center
-- Cloud Development Project Center
-- HTML5 Development Center
-- Windows Mobile Development Center
|