Simple question with simple answer ?Simple question with simple answer ?
Old forum URL: forums.lhotka.net/forums/t/115.aspx
AdrianE posted on Tuesday, May 16, 2006
Hello,
I'm analyzing the possibility of using CSLA for my development efforts but I'm having some doubts about some simple things.
I'm developing only for web platforms but they are not massively accessible (intranet applications with a few hundreds users base) so I'm not very concerned about the object-oriented overhead.
The doubts I have might seem very simple (in fact they could be very simple) but I'd like to be sure before embracing CSLA.
The example I'd like to talk about is this:
1. I have a Customer that lives in a City which is in a Province which is in a Country.
The question is how do I implement a business model for this without replicating all the code needed to load the data from the database and without incurring in the performance penalty of having to call 4 stored procedures to display a customer (one to retrieve customer data, and another one for each of the City, Province and Country data).
The two approaches that come to my mind (that obviously don't address both needs at the same time) are:
1.
Have a Customer object that loads it data only and contains a property of type City than when accessed loads its data (lazy initialization) and it has a property of type Province and this has a property of type Country.
This approach maintains hidden the need to access Customer child properties data but incurs in a performance overhead because of the need to make a stored procedure call for each child data. The need to hide the code needed to access the data may seem unreasonable but if you start analyzing it you may end up with lots of stored procedures having to make the join between the City, Province and Country tables which in other examples could involve many more tables.
2.
Have a Customer object that loads its data from the database, plus the data needed to load the City, Province and Country, and passes that information through the DataReader or another DataSource-agnostic object (for example a Hashtable or Dictionary).
This approach is very performant but it starts to replicate JOINS all around the stored procedures. And if the Customer has to load its Contacts, it also has to make the JOINS between the Contacts and the City, Province, Country which gets too complex for loading 4 simple entities.
Any help would be very appreciated.
If something is not very clear, please tell me and I'll try to make it clearer.
Thanks in advance,
Adrian
CaymanIslandsCarpediem replied on Tuesday, May 16, 2006
In cases like this if there are "decode" objects which I know will be used all the time (countries), I will create the objects as static (C# terminology cannot remember VB.NET term off the top of my head). As such, the first time they are needed they make the call to the DB to populate but on any call after that they are already populated in memeory so no additional DB call is needed.
One thing to remember about this is, if another user has added a new "decode" which you have stored in memory you may not have this record so there may be cases when you need to refresh the in-memory decode collection.
MichaelBosch replied on Tuesday, May 16, 2006
Static = Shared in VB
I'd say it depends on what you're doing with the Customer object.
If it's a read-only object that you don't really need to modify their
city/state/country info, it might be best to have these as simple
string variables that you load from the database with all the inner
joins. This might be more of a CustomerInfo object. You may also
want to have a private variable that gets loaded from the stored
procedure, for example m_CountryID, then another property called
CountryName that returns something like
CountryList.GetCountryList.Item(m_CountryID).CountryName.
CountryList might also have the shared (static) object reference like
Cayman suggested. I guess the point is, you have a few options.
xal replied on Tuesday, May 16, 2006
Adrian,
I'm not sure I get what you're saying. Yes, you can have one stored proc with all results for the root and the children or you can lazy load them and have one sp for each object. The joins will have to be there anyway...
This is something you'll have to face wheather you go with csla (or any object oriented app) or with a non object oriented app.
How else would you do it?
AndrésAdrianE replied on Tuesday, May 16, 2006
Andrés,
The joins are not necessary if you apply the lazy loading since when you load the child object, it receives its Id so it only loads itself from it’s table without joins.
Here’s an example:
SELECT * FROM Customer WHERE IdCustomer = 4
(loads Customer data (without children data))
When the City’s name property is accessed it executes:
SELECT * FROM City WHERE IdCity = 25
(where the IdCity was obtained on the first SELECT because it’s part of the Customer data)
In this way I didn’t make any joins as opposed to:
SELECT * FROM Customer INNER JOIN City ON …. WHERE IdCustomer = 4
Which would have been needed to load the Customer and City data whit only one stored procedure call.
Adrián
xal replied on Tuesday, May 16, 2006
I see your point, but if you're lazy loading you would probably want to go with the joins anyway, since if the user requests the country information, and you have separate city and province objects, you'd need to load the city first, then the province and finally the country... You will end up writing a lot of code checking for nulls, you will make unnecesary db calls and it will make you wish you've done the joins in the first place
Just my 2 cents
Andrés
AdrianE replied on Tuesday, May 16, 2006
Andrés,
I understand what you mean and that was my first thought but look how it starts to grow (and just for simple entities)
[dbo].[Contacto]
INNER JOIN [dbo].[TipoContacto] ON [dbo].[TipoContacto].[IdTipoContacto] = [dbo].[Contacto].[IdTipoContacto]
INNER JOIN [dbo].[Domicilio] ON [dbo].[Domicilio].[IdDomicilio] = [dbo].[Contacto].[IdDomicilio]
INNER JOIN [dbo].[Ciudad] ON [dbo].[Ciudad].[IdCiudad] = [dbo].[Domicilio].[IdCiudad]
INNER JOIN [dbo].[Provincia] ON [dbo].[Provincia].[IdProvincia] = [dbo].[Ciudad].[IdProvincia]
INNER JOIN [dbo].[Pais] ON [dbo].[Pais].[IdPais] = [dbo].[Provincia].[IdPais]
It starts to be pretty unmanageable, think about an Invoice that has a customer that has a city that has a ...
Adrián
ajj3085 replied on Tuesday, May 16, 2006
I'm not sure if this is an option for you, but perhaps you could create a view, and do your select from that view?
I've done that when joins would have become too complex, its worked pretty well.
HTH
Andy
xal replied on Tuesday, May 16, 2006
Adrian,
El problema es que tenés una jerarquía muy profunda! (oops, sorry!)
You should try flattening your hierarchy. It's usually not a good idea to have such a deep object model and it's generally not even neccesary.
Try revising your use cases! It get's hairy when you go further than grandchildren.
I usually avoid going further than child objects. Grand children already make it complex.
Besides you wouldn't want to edit your customer information from withing an invoice. You'd open a customer object.
You wouldn't want to edit a city from a customer either, you create a city root...
The fact is that you're just displaying information that affects the customer.
I'd go for a client object that has a child collection of addresses that displays has an address and a city value (it's id and / or description). It doesn't have to know anything about province and country. That's just data you can use to filter the list cities so that the user can pick one and it usually is more of a ui problem (in most cases). Your object only has to worry about taking a valid city. You can also have read only province and country fields if you find it convenient.
Again, that's just the way _I_ would do it. Some may disagree.
Andrés
DavidDilworth replied on Wednesday, May 17, 2006
I'm going to agree with Andres and repeat the often quoted mantra "objects are defined by behaviour not data".
What is it you're trying to do with your Customer object? Just view it? Edit it?
Perhaps you need two versions of your Customer object, an Editable one and a Read-Only one?
Do you really trying to embed a whole "Country" object inside your "Customer" object?
Perhaps you want a Country object for editing the countries in your application. And a Customer object which exposes a CountryName property, which is the name of the country the customer is in. And a NameValueList of Country objects which can be used in your "Edit Customer" form to allow the customer to be linked to the right Country.
The choice depends on what your business requirements dictate.
HTH
Copyright (c) Marimer LLC