Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ADO.NET / 3-Tier architecture question

0 views
Skip to first unread message

Matt Porco

unread,
Aug 19, 2002, 6:07:54 PM8/19/02
to
I've read a lot of posts here about using ADO.NET objects in a 3-tier
architecture, and I think the overall consensus is that there is no
one best practice, but rather many possible practices depending on
your situation. So I'm looking for a little idea validation. Here's
my situation:

I'm developing a 3-tier app that will initially be Windows forms with
an OleDB or SQL backend in a LAN environment, but will eventually be
ported to use ASP.NET in an browser/Internet scenario. The database
will not be huge (maybe 20K-30K customers max with associated
appointments, transactions, etc.) The initial architecture is as
follows:

Presentation (Windows Forms)
|
Business (Custom objects)
|
Data (SQL or OleDB)

My thinking was to have the data layer pass datasets up to the
business layer, then have the business layer expose business objects
to the presentation layer. I think this all fits in with generally
approved practice. However, my question concerns the technical
implementation at the business layer.

If the data layer is passing datasets up to the business layer, then
what should I do with these datasets? Here are the two options that I
have thought of:

(1) Keep the dataset and use it in lieu of fields to store the
business object's data. Thus I would expose its datatables/rows
through properties of the business objects (so for example, class
"Customer" has property "HomePhone" which returns
CustomerDS.Tables("Customers").Rows(CustomerID).Item("HomePhone") or
the strongly-typed equivalent). Then send the modified dataset back
to the data layer for updating via a DataAdapter.

Advantages: Simpler design. Uses ADO.NET objects pretty much the way
they were intended to be used. Probably faster.

Disadvantages: Business objects can't use inheritance (i.e. can't make
a Customer class inherit from a Person class, because we can't use
fields to store the Person class data). This is really a result of
associating business objects directly to database tables in this
design. Also have a new dataset for every new business object created
(which could really add up).

(2) Use the dataset to populate fields in the business object and then
dispose of it. Then when/if the business object needs to update the
database, create a new dataset with the same schema, populate it with
the object's fields, then send the dataset to the data layer for
updating.

Advantages: More flexible because business object design does not have
to correspond to database design so much. Can use inheritance in
business objects. Less datasets held in memory.

Disadvantages: Slower because of extra overhead and creating new
dataset for each update. Have to write my own DataAdapter since the
dataset being sent from the business layer to the data layer won't
really be "accurate" (i.e. it will contain rows with rowstate "Added"
but that actually exist the database). Isn't really using ADO.NET the
way it was designed to be used (<-- do you think this is true?).

Now some of you might say "why do you need separate business objects
at all - just use strongly typed datasets as your business objects".
I don't like this idea because (a) it makes the business object design
too wedded to the database design, and (b) it doesn't allow for data
transformation and validation at the business layer.

Sorry for all the detail, but I've spent a lot of time thinking about
all of this. My question is: have I correctly summarized the
pros/cons of these methods or am I missing something(s) big? Are
there other methods I have not outlined that would work better?

Thanks all.

Matt Porco
Virtuosic LLC

Etienne Charland

unread,
Aug 19, 2002, 6:36:34 PM8/19/02
to
Here's how I'm implementing N-Tier in my application. It really works great.
I have the 3 standard projects(presentation, business, data access) and I
add another project with the typed datasets and other informations(or
structures) that needs to be shared between layers. Now... all the data pass
between layers as datasets. So, when I request data from the business layer,
it requests it from the data access layer, then pass the dataset back to the
presentation layer. I can then bind the data to my form or do whatever I
want in both layers.

To update data, you have 2 choices (that I think of).
1) In your data access layer, you can have a dataadapter with all the update
commands. In the presentation layer, you pass a dataset to the business
layer containing the changes in the dataset (newDataSet =
myDataSet.GetChanges). Then, in the business layer, you validate the data on
each updated or added row, then once everything is ok, you send it to the
data access layer where it will acually update.
2) In your business layer, you have procedures to add, update or delete
rows. For example:
Public Sub AddCustommer(ID As String)
Public Sub DeleteCustommer(ID As String)
Public Sub UpdateCustommer(Row As mySchema.CustommerRow)

In the way I designed my application, the 2nd solution works better.

By the way, you shouldn't bother about creating many datasets. If top
performance is *really* essential, then you could test to see how much time
it takes to work with datasets, but I don't think it takes much.

Another thing: use SQL Server, not Access.

If you have other questions, feel free to ask.

"Matt Porco" <ma...@virtuosic.com> wrote in message
news:8de5445.02081...@posting.google.com...

Oliver Eilhard

unread,
Aug 20, 2002, 3:06:57 AM8/20/02
to
Hi Etienne, hi Matt!

I must agree to Etienne's way of doing things. As it certainly
depends on your specific application, we found that the best
way of doing things in a database centered application is to pass
datasets between the layers. In our first architecture we omitted
datasets because of the performance loss we expected. But we
gained more flexibility and development speed by using datasets
and therefor accepted some performance loss.
Datasets are very flexible. You can apply business rules to the
(in-memory) dataset on any layer. You get tremendous response times
in scenarios where you do one trip to the database and then only do
some filtering, sorting or grouping. And you get many things for free
just by binding DataViews or DataTables to web or windows controls.

Oliver


Matt Porco

unread,
Aug 20, 2002, 12:15:49 PM8/20/02
to
"Oliver Eilhard" <oliver...@eilhard.net> wrote in message news:<OP$8LgBSCHA.3500@tkmsftngp12>...

Thanks for the info, but my question goes beyond just wondering
whether or not to pass data between layers as datasets. I'm more
wondering how the business objects could interact with the datasets.

(1) If you use a dataset to store a business object's properties, how
do you handle inheritance? In other words, say you have the following
business objects:

Public Class Person
Public FirstName as String
Public LastName as String
End Class

Public Class Customer
Inherits Person
Public CustomerID as Guid
Public BirthDate as DateTime
End Class

Public Class MedicalCustomer
Inherits Customer
Public SSN as String
Public PrimaryPhysicianName as String
End Class

As you can see, each class builds on the functionality of the higher
level class (as any good OO design should). This is necessary for me
since the object hierarchy I'm building will be used by different
applications for different purposes. In this scenario, it seems to me
that fields are the most logical (and really the only) way to store
each object's data. I don't see how to do it with a dataset.

(2) If I was to create a single dataset for every new instance of an
object, wouldn't that create tons of datasets when you have a
collection of business objects? For example, assume we have the
classes listed above and we add a Public Class CustomerCollection
which is a collection of Customer objects. If each Customer object
had its own dataset, then I would be creating 1000's of datasets if I
had 1000's of customers! It would make more sense to have a single
dataset for the collection with datarows for each client, but then how
does this work with passing a dataset for each Customer object?

Also, I don't like the idea of passing a dataset to the presentation
layer. If you're doing that, then why have business objects at all?
Just do your data transformation/validation at the data layer with
stored procs or strongly typed datasets.

It seems to me that there are some fundamental problems with creating
a truly OO design that incorporates ADO.NET. Am I the only one that
sees this?

Oliver Eilhard

unread,
Aug 20, 2002, 2:24:38 PM8/20/02
to
Matt,

> (1) If you use a dataset to store a business object's properties, how
> do you handle inheritance?

While I never thaught about it really, you could easily create a class
around e.g. a DataRow that does all sorts of stuff for you (e.g. casts).
Pass a DataRow to the internal constructor and the class does the rest.
Of course this only works if your data source reflects inheritance in a
way that is compatible with that method.


> As you can see, each class builds on the functionality of the higher
> level class (as any good OO design should). This is necessary for me
> since the object hierarchy I'm building will be used by different
> applications for different purposes. In this scenario, it seems to me
> that fields are the most logical (and really the only) way to store
> each object's data. I don't see how to do it with a dataset.

There is a very good preview of a book from Martin Fowler
on http://www.martinfowler.com/isa/. He compares different scenarios and
patterns of "Enterprise Application Architecture". It also has some pretty
good chapters on how to do it with .NET and the DataSet.

In the last projects we did exactly what you did and built lots of
classes that reflect objects from the problem domain. We always ended
up writing a lot of code just for the sake of a "clean" OO design. While
everything works alright, we took a different approch in our latest
project. And we are quite surprised on how much lines of code we saved
by using "the DataSet approach". Furthermore, if you build the front-ends,
you can use data binding and save even more work. But the project is
not finalized and most of our projects are very data-centric, so I can only
give you my personal expression right now.


> (2) If I was to create a single dataset for every new instance of an
> object, wouldn't that create tons of datasets when you have a
> collection of business objects? For example, assume we have the
> classes listed above and we add a Public Class CustomerCollection
> which is a collection of Customer objects. If each Customer object
> had its own dataset, then I would be creating 1000's of datasets if I
> had 1000's of customers!

Creating a dataset for every single customer it definitely an overhead.
But why having a DataSet for every object when a object most of the time
is just a row in your data source.

On the other hand, you can also use a DataReader, if you don't need
the additional features of the DataSet. It's a forward-only cursor for
your data source. You can scroll through the resultset and create your
objects on the fly.

You may also take a look at ObjectSpaces, which is about to be coming
from Microsoft (although I don't know a release date). It connects objects
to the datasource by reflection and attributes. You may ask Google for
more information on it.


> Also, I don't like the idea of passing a dataset to the presentation
> layer. If you're doing that, then why have business objects at all?

Yes! Sometimes it's not even necessary. I'm not a OO advocate.
I'm just using its concepts because it solves many of my problems.

Passing datasets to the presentation layer has several benefits.
E.g. your clients can sort and filter it via a DataView and so you don't
have to code that in your business layer.


> Just do your data transformation/validation at the data layer with
> stored procs or strongly typed datasets.

Don't get me wrong, but I prefer the power of a high-level language
instead of using T-SQL or PL/SQL for things that they just weren't
build for... ;-)

Oliver


Cecil Howell

unread,
Aug 23, 2002, 9:02:48 PM8/23/02
to
Matt, I have been struggling with this same question. I really wanted to
use strongly typed DataSets as my Business objects to take advantage of
binding as well as because they already accomplished so much of what a
business object should have, especially if you use annotations to control
the naming of the properties and methods. As for your two concerns:

> Now some of you might say "why do you need separate business objects
> at all - just use strongly typed datasets as your business objects".
> I don't like this idea because (a) it makes the business object design
> too wedded to the database design, and (b) it doesn't allow for data
> transformation and validation at the business layer.

(a) Strongly typed DataSets are not wedded to the design of the database
because they use a DataAdapter for all interaction to back end Database.
The DataAdapter is the only thing that sees the backend.

(b) This was what really stumped me. How to get validation done in DataSet.
I fooled with it for a while and was frustrated until I read this article
from Visual Studio Magazine, it was the answer to my prayers! Check it out,
I have not finished implementing it yet but it seems like a great
architecture.
http://www.fawcette.com/vsm/2002_07/magazine/features/dollard/default.asp
--
Cecil Howell
ceciltech
cecil^@Ceciltech.com
Replace ^ with h


"Matt Porco" <ma...@virtuosic.com> wrote in message
news:8de5445.02081...@posting.google.com...

Tom

unread,
Aug 25, 2002, 9:15:04 AM8/25/02
to
> Matt, I have been struggling with this same question. I really wanted to
> use strongly typed DataSets as my Business objects to take advantage of
> binding as well as because they already accomplished so much of what a
> business object should have, especially if you use annotations to control
> the naming of the properties and methods. As for your two concerns:

I use an architecture where I put the DataSet and the Adapters in one
project. Call it DAL. Then I create a business-layer that implements
mediator-classes for the DataSet-tables and a type of factory builder. I
cater the mediator classes' properties with attributes, to enable some
clients to extract additional information, such as localized category-names,
descriptions, and so on. The resource-manager is contained both in the
business-layer and the client-layer, due to me having to workaround some
issues. It also results in the application-code not being that bound to the
client interface. The mediator classes are necessary for my more
culture-sensitive localization. Since it sits between the client and the
data-layer, they need to be able to interpret the indata and get correct
outdata. For example, if I want to display a currency-string from a
"money"-field in the database, I might need this property in a
mediator-class:

// Add custom data-validation in here. Each mediator class implements the
IMediator object so I can do quick operations
public class EconomicalResult : IMediator
{
private DataRow dataRow;

public EconomicalResult(DataRow dataRow) {
this.dataRow = dataRow;
}

[LocalizableCategory("Finance"), LocalizableDisplayName("Total cost")]
public string TotalCost {
get {
// return the internal DataRow's TotalCost column as a string
formatted for currency
return this.dataRow["TotalCost"].ToString("c");
}

set {
// parse the value as a currency string
this.dataRow["TotalCost"] = decimal.Parse(value,
NumberStyles.Currency);
}
}

[LocalizableCategory("Finance"), LocalizableDisplayName("Total time")]
public decimal TotalTime {
get {
return Convert.ToDecimal(this.dataRow["TotalTime"]);
}
set {
this.dataRow["TotalTime"] = decimal.Parse(value);

// the totaltime changes, thus the total cost will change
MyCalculations calc = new MyCalculations(this.dataRow.Table.DataSet);
calc.UpdateValues();
calc.Dispose();
}
}
public IMediator : Delete() {
this.DataRow.Delete();
}
}

Since the DataSet is built for the invariant-culture, as it should be. A
"money" value that's 1234567 should depending on the culture be properly
displayes. In example, Swedish vs US:

// Swedish
1.234.567,00 kr

// US
$1,234,567.00

These use different comma-separators, so you need code to convert between
the two. And you need code to ensure that no strings get into the database
field. You could bloat the DataSet with this. But I choose not to. If you
run on the Swedish culture and you take the US string "1,234,567.00" and you
try to convert it to a decimal, you'll receive a runtime error. Other things
that you might to convert between in response to cultures are units of
measurement, weight, area, and so on. You'll want to store, for example,
measurement-data in one given unit in the underlying database. Let's say you
save it as inch and foot. When the culture is Germany, you'll need to
convert it to centimetres and metres. Do you do this in the DataSet? The
underlying value stored in the DataSet should be simply inch and foot. The
values returned from it will be in inch and foot. And across several
machines, such a 3-tier, you'd need to pass the culture-info across
boundaries in order to keep tabs of what unit of measurement the client is
set for. It makes more sense to me to keep a clear business-layer on top of
the DataSet that deals with these kinda things, validates to see if it went
right, and if it did, sets the values in the DataSet. You'll run into a very
bloated DataSet otherwise. I'm not saying it can't be done in the DataSet.
The point is it might be easier to keep a business-layer separate for these
things. I know that it'll definitely be easier if you're a team working on
the code and use some type of source-sharing like Visual Source Safe.

Back to the mediator-pattern. I set up a method in the business-layer that
takes a DataRow, examines it via GetType() and returns the correct mediator
class for it. There are several business-requirements that determine what
mediator class to return, and what properties should be visible. There's
also an "ObjectBuilder" class in the BLL that the clients can put together
and send in to a factory that returns a mediator object with default values,
that you later perform your operations on. This builder has the advantage or
selecting different default values, depending on what previous
business-requirements have been filled. It can also reject the
object-creation depending on business-requirements.

Keep in mind that the DataLayer might want to return several different
DataSets. I.e. one for listing available documents in a database. One that
represents a document, etc. I keep this layer simple, providing in core only
an Update(dataSet) method that calls update on all adapters in addition to
Get(ID) that does a select on all adapters and returns a document. These are
called by an instance of the business object. It's actually quite a complex
Windows Forms project, out of scope for covering it all here. But I did do a
lot of thinking before getting started, and it has worked pretty well so
far. The business-layer use internal methods (as not seen above) to format
the currency-strings. These objects are also registered as XsltExtension
objects later and utilized by the Windows Forms UI (which embeds Internet
Explorer) when transforming the result of dataSet.GetXml() into HTML.

I only use the OnRowChanged() event once. And it's actually a pain to rely
on it, since the strongly typed classes are regenerated once you rebuild the
dataset. Or when someone else does. It screws up the complete application.
Furthermore, separate BLL objects are quite good to have when you want to
have a loosely coupled system that uses maybe MSMQ or BizTalk. You can
perform all your actions within the BLL layer and do something sensible when
things go wrong. And in the BLL layer, you can handle your typed DataSet
exceptions gracefully.

Anyway, that's some thoughts based on my adventures. I hope it helps!

Tom


Kathleen Dollard

unread,
Aug 26, 2002, 9:11:39 AM8/26/02
to
Tom,

Couple of questions

> I use an architecture where I put the DataSet and the Adapters in one
> project. Call it DAL. Then I create a business-layer that implements
> mediator-classes for the DataSet-tables and a type of factory builder.

Are the DAL DataSets loosely typed? Are your mediator classes strongly
typed? Did you manually build your mediator classes? If your doing code gen,
how (roughly) are you doing it?

> Since the DataSet is built for the invariant-culture, as it should be. A
> "money" value that's 1234567 should depending on the culture be properly
> displayes. In example, Swedish vs US:

This all looked good. You support different countries, but do you have to
support different business rules? If so, how do you incorporate that (taxes
for example).

It makes more sense to me to keep a clear business-layer on top of
> the DataSet that deals with these kinda things, validates to see if it
went
> right, and if it did, sets the values in the DataSet. You'll run into a
very
> bloated DataSet otherwise. I'm not saying it can't be done in the DataSet.
> The point is it might be easier to keep a business-layer separate for
these
> things. I know that it'll definitely be easier if you're a team working on
> the code and use some type of source-sharing like Visual Source Safe.

Did you mean the DataSet or the database itself in this paragraph? I agree
if you meant the database. If you meant the dataset, that implies a
programmer designed strongly typed DataSet (something I have been workign
on) and therefore presents exactly the same amount of code.

> Back to the mediator-pattern. I set up a method in the business-layer that
> takes a DataRow, examines it via GetType() and returns the correct
mediator
> class for it.

Depending on how often you are doing this, you might want to explore "Is"
instead of reflection. The performance of reflection is slow, although it
certainly makes elegant solutions.

> Keep in mind that the DataLayer might want to return several different
> DataSets. I.e. one for listing available documents in a database. One that
> represents a document, etc. I keep this layer simple, providing in core
only
> an Update(dataSet) method that calls update on all adapters in addition to
> Get(ID) that does a select on all adapters and returns a document.

This seems to imply that you have a one to one mapping between tables and
datatsets. If you do I am wondering why? That would imply that you are not
using Relations. If you aren't, I am wondering how you are doing relation
based operations such as cascading primary keys.

> I only use the OnRowChanged() event once. And it's actually a pain to rely
> on it, since the strongly typed classes are regenerated once you rebuild
the
> dataset. Or when someone else does. It screws up the complete application.


Assuming you mean the ADO.NET strongly typed dataset generator...Actually,
this problem can be easily avoided, and I should have included it in the
article someone else referenced. You can derived the DataSet itself (you can
actually derive the tables, rows, etc, but you can't instnatiate them
without modifying autogen code). Within the derived dataset, you can set
those events to call any handlers you want. These would be middle tier
handlers you would use anytime you touched data (quite a nice gatekeeper),
separate from your UI handlers.

> Anyway, that's some thoughts based on my adventures. I hope it helps!

Thanks for the explanation. Looking forward to hearing more about your
design. I have spent a lot of time in this in the last nine months and I
think I have built about 29 data layers. The underlying complexity is that
for middle tiers, one size most definitely does not fit all, and I am
working on some preliminary guidelines (this work is just barely started) as
to how to select an approach that fits the project or organization.

Kathleen

Kathleen Dollard

unread,
Aug 26, 2002, 9:16:05 AM8/26/02
to
Cecil,

Glad the article helped. If you have any questions, I am trying to be active
in this group again after a long series of minor but overwhelming crises.

Kathleen


Tom

unread,
Aug 26, 2002, 1:13:03 PM8/26/02
to
Hi Kathleen!

> > I use an architecture where I put the DataSet and the Adapters in one
> > project. Call it DAL. Then I create a business-layer that implements
> > mediator-classes for the DataSet-tables and a type of factory builder.
>
> Are the DAL DataSets loosely typed? Are your mediator classes strongly
> typed? Did you manually build your mediator classes? If your doing code
gen,
> how (roughly) are you doing it?

The DataSets are strongly typed. The mediator classes are not as strongly
typed. In example, when I return a currency value, the symbols are not valid
decimals, so I need to parse it to a string. Similarly, when receiving a
currency-string I need to use NumberStyles and decimal.Parse() to get an
invariant decimal type. I used a perl-script to parse the schema of the
DataSet in order to extract a rough outline of the classes. Of course there
were errors, but I used Perl to generate all TypeConverters, Custom UI
classes, and a strongly typed resource-manager derivation (where the resX
entries are exposed as properties). :-)

> > Since the DataSet is built for the invariant-culture, as it should be. A
> > "money" value that's 1234567 should depending on the culture be properly
> > displayes. In example, Swedish vs US:
>
> This all looked good. You support different countries, but do you have to
> support different business rules? If so, how do you incorporate that
(taxes
> for example).

We don't use exact pricing. We measure performance and economical savings
from it. Anyhow, the actual prices for the items sold normally come from the
in-house web services system. The nitty-gritty details of it has been in
place for quite some time, so we're fortunately sheltered from any details
from using it in our application. :-) The application we wrote sets up a
simulation of time and money saved during operations based on input from the
client.

> > Back to the mediator-pattern. I set up a method in the business-layer
that
> > takes a DataRow, examines it via GetType() and returns the correct
> mediator
> > class for it.
>
> Depending on how often you are doing this, you might want to explore "Is"
> instead of reflection. The performance of reflection is slow, although it
> certainly makes elegant solutions.

Cool! I did GetType()==typeof(someType) but I'll try the "is" and see what I
get. Reflection is way cool. I use it for a custom transaction-manager that
takes an object and puts the property-names and values of a mediator object
into a hashtable. I actually didn't try and serialize these objects, since
DataRow's can't be serialized. Maybe this bypasses it? I don't know.

> This seems to imply that you have a one to one mapping between tables and
> datatsets. If you do I am wondering why? That would imply that you are not
> using Relations. If you aren't, I am wondering how you are doing relation
> based operations such as cascading primary keys.

No, it's not a one-to-one mapping.

> Assuming you mean the ADO.NET strongly typed dataset generator...Actually,
> this problem can be easily avoided, and I should have included it in the
> article someone else referenced. You can derived the DataSet itself (you
can
> actually derive the tables, rows, etc, but you can't instnatiate them
> without modifying autogen code). Within the derived dataset, you can set
> those events to call any handlers you want. These would be middle tier
> handlers you would use anytime you touched data (quite a nice gatekeeper),
> separate from your UI handlers.

> ... <cut in> ...


> Thanks for the explanation. Looking forward to hearing more about your
> design. I have spent a lot of time in this in the last nine months and I
> think I have built about 29 data layers. The underlying complexity is that
> for middle tiers, one size most definitely does not fit all, and I am
> working on some preliminary guidelines (this work is just barely started)
as
> to how to select an approach that fits the project or organization.

> ... <cut in> ...


> Did you mean the DataSet or the database itself in this paragraph? I agree
> if you meant the database. If you meant the dataset, that implies a
> programmer designed strongly typed DataSet (something I have been workign
> on) and therefore presents exactly the same amount of code.

I put these paragraphs together. The initial "gatekeeper" solutions produces
pretty much the same thing that the mediators do. I've redesigned the typed
dataset several times, but in comparison, hardly touched the mediator
objects. The mediators were actually a good initial object to put up
according to the business specifications. The constructors take the
datarow(s) that it's designed to present data on, letting me "merge" several
related records into a single view when needed. It's displayed, for example,
in the windows forms propertygrid. Like in VS, a treeview above it is
generated from parsing the current MDI child's DataSet. Once a node is
selected, the appropriate mediator object is instantiated. There, I'm
benefiting from the properties' attributes for localized friendly property
name (based on Cali's code), localized category-names, and localized
descriptions, in addition to typeconverters and custom controls that pop up.
All designated from the mediator. Each property that displays a monetary
string, uses a method for producing a valid currency-string, as mentioned. A
property that displays metric data, calls functions to convert between
metric/inch. Properties displaying weight convert between kilos and pounds.
Controlled by the current culture. The minstantiated objects are also easily
bound to other controls in the UI, such as textboxes, just like DataRows.

Absolutely right that one size doesn't fit all. :-) There's a lot of things
that plays in.

Tom


Cecil Howell

unread,
Aug 26, 2002, 4:51:20 PM8/26/02
to
Tom,
I experimented with custom business objects that exposed properties and
had one major problem in binding. If the value of a bound textbox changed
the property was updated, but if the value of the underlying property
changed, through code, the bound control did not update to reflect new data.
If you are binding properties of your custom business object have you found
a way around this?

--
Cecil Howell
ceciltech
cecil^@Ceciltech.com
Replace ^ with h

"Tom" <for...@about.it> wrote in message
news:eElk0OSTCHA.1632@tkmsftngp11...
<<SNIP>>


> The minstantiated objects are also easily
> bound to other controls in the UI, such as textboxes, just like DataRows.


>

<<SNIP>>
> Tom
>
>


Kathleen Dollard

unread,
Aug 28, 2002, 11:09:37 AM8/28/02
to
Tom,

> The DataSets are strongly typed. The mediator classes are not as strongly
> typed. In example, when I return a currency value, the symbols are not
valid
> decimals, so I need to parse it to a string. Similarly, when receiving a
> currency-string I need to use NumberStyles and decimal.Parse() to get an
> invariant decimal type. I used a perl-script to parse the schema of the
> DataSet in order to extract a rough outline of the classes. Of course
there
> were errors, but I used Perl to generate all TypeConverters, Custom UI
> classes, and a strongly typed resource-manager derivation (where the resX
> entries are exposed as properties). :-)

So your auto-gen was one off followed by manual tweaks, which means you plan
to do manual changes if you add a new column,for example?

> We don't use exact pricing. We measure performance and economical savings
> from it. Anyhow, the actual prices for the items sold normally come from
the
> in-house web services system. The nitty-gritty details of it has been in
> place for quite some time, so we're fortunately sheltered from any details
> from using it in our application. :-) The application we wrote sets up a
> simulation of time and money saved during operations based on input from
the
> client.

K. I am wodering about using the users settings rather than specifying the
currency in a config file for the installation. Haven't worked with this and
could see advantages both ways.

> > This seems to imply that you have a one to one mapping between tables
and
> > datatsets. If you do I am wondering why? That would imply that you are
not
> > using Relations. If you aren't, I am wondering how you are doing
relation
> > based operations such as cascading primary keys.
>
> No, it's not a one-to-one mapping.

> I put these paragraphs together. The initial "gatekeeper" solutions

Sounds interesting. I am wondering where you are putting relations
definitions ifyou are using one to one mappings between datasets and
dataadapters?

Kathleen


Tom

unread,
Aug 28, 2002, 4:44:56 PM8/28/02
to
> I experimented with custom business objects that exposed properties
and
> had one major problem in binding. If the value of a bound textbox changed
> the property was updated, but if the value of the underlying property
> changed, through code, the bound control did not update to reflect new
data.
> If you are binding properties of your custom business object have you
found
> a way around this?

I think I see what you mean. Since I do all value-changes within the classes
that are bound, and not from the "outside" (like the form that host the
bound controls), I've not run into that problem. Sorry I couldn't give a
better answer.


Tom

unread,
Aug 28, 2002, 4:53:52 PM8/28/02
to
> So your auto-gen was one off followed by manual tweaks, which means you
plan
> to do manual changes if you add a new column,for example?

Yes, and likewise if I need to add another attribute to a property, like a
TypeConverter. It has to be done manually. It would have been a more
sophisticated script if there was enough time during the day. :-)

> K. I am wodering about using the users settings rather than specifying the
> currency in a config file for the installation. Haven't worked with this
and
> could see advantages both ways.

Not sure if there's a question in there. User's settings default to the
culture currently running the first time the app is run. It's kept in a
class which is serialized and used as a config file. A "customize" window
enables them to altercate the settings and re-serialize the class. When the
client creates a new document, the currency selection is written to the
DataSet and stored there. Otherwise the monetary data would, of course, be
invalid if in example a US document on a German computer interpreted the
dollar values as Euro.

> Sounds interesting. I am wondering where you are putting relations
definitions ifyou are using one to one mappings between datasets and
> dataadapters?

The dataset that I call "document" has approx. 15 tables. It's hierarchical
and nested, full of relations, reflected in the typed dataset (like
GetXXXParentRow). Each table has a data-adapter associated to it. Via SQL
queries each adapter fills each table in the DataSet, using the primary key
of the "root"-table.

Best,

Tom

Cecil Howell

unread,
Aug 30, 2002, 11:18:51 AM8/30/02
to
Kathleen, Tom
I was trying both of your approaches. I had two major problem when I
tried Toms approach:
1) It seemed like I was creating a lot of extra code to duplicate
much of what the strongly typed dataset already gave me.
2) Binding was a major problem when you create a new bussiness object
and then want to bind to it instead of your previous object. I solved this
by always using the same object and having SelectCustomerByID() method that
changed which Customer row the existing object represented, but then the
form would not reflect that change to the properties. I could find no way
to have my bussiness object force the bindings to update, I had to force the
updating in the UI.

Tom- Does your architecture address these?

With Kathleen's approache my main issue was that I had to wait until the
currency manager current record was changed to get the validation to be
triggered in my extended dataset, that was too late.
Kathleen's article adressed this plus gave me the bonus of the error
provider which I was using but without binding, the binding on the error
provider is fantastic!

Kathleen- There is a lot of extra code that is added to the form to get your
architecture to work. I have created a base form that encapselates much of
the work, but I was thinking that maybe the extended dataset could actualy
do this work instead i.e. have a method that excepts a form object and
returns the bindingmanager all set up and even a method that returns the
errorprovider all bound! Have you considered either of these two
approaches? Could you comment if you have?

--
Cecil Howell
ceciltech
cecil^@Ceciltech.com
Replace ^ with h

"Tom" <for...@about.it> wrote in message

news:uCV5JlDTCHA.1996@tkmsftngp12...

Kathleen Dollard

unread,
Aug 30, 2002, 5:26:49 PM8/30/02
to
Tom,

Thanks for your clarification on both the culture and the one-one mapping
issue

Kathleen


Tom

unread,
Sep 1, 2002, 5:24:17 AM9/1/02
to
> 1) It seemed like I was creating a lot of extra code to duplicate
much of what the strongly typed dataset already gave me.

I needed to "merge" several tables into 1 object almost all the time to put
together the object the client wants. Clients come from different industrial
segments, so the "common" properties in a table, like "Diameter", have
different meaning, behavior, and formulaes for being calculated. I need to
account for these segments mainly in the set-methods of the mediator-object,
get/set-methods account for adjusting for current culture and other rules of
formatting and conversion, and the object-properties are tagged with custom
attributes. By having a mediator, I need to check the type of industrial
segment when I get the object. Once I have it, the logic is is handled by
the object. I do not need to check the type of industrial segment everytime
I do a "set"-operation on the Diameter-column. When the business-requiements
change, I adjust the mediator class.

> 2) Binding was a major problem when you create a new bussiness
object and then want to bind to it instead of your previous object. I
solved this
> by always using the same object and having SelectCustomerByID() method
that changed which Customer row the existing object represented, but then
the
> form would not reflect that change to the properties. I could find no way
to have my bussiness object force the bindings to update, I had to force the
> updating in the UI.
>
> Tom- Does your architecture address these?

I am definitely not a databinding-expert, so I have no idea how this is
solved. Probably the guys at the databinding NG can answer your question.
:-)


0 new messages